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
codecin/cin.py
ADDED
|
@@ -0,0 +1,2558 @@
|
|
|
1
|
+
"""CIN 高级语言编译器。
|
|
2
|
+
|
|
3
|
+
将 CIN 源码 (类 C 语法: 函数/struct/多维数组/字符串/浮点/控制流)
|
|
4
|
+
编译为 Code CIN 字节码 IR。
|
|
5
|
+
|
|
6
|
+
语法扩展 (2026):
|
|
7
|
+
- 语句: break/continue, do-while, switch/case/default (case 常量表达式)
|
|
8
|
+
- 表达式: ?: 三目 (短路), ++/-- 前缀与后缀, 复合赋值 += -= *= /= %=
|
|
9
|
+
- 字面量/类型: 0x/0b/0o 进制与 u/L/f 后缀、数字下划线、字符字面量 'a';
|
|
10
|
+
char/short/long/unsigned 类型别名 (64 位槽模型, 与 int 同宽)
|
|
11
|
+
- 内建: int_to_str/itoa, float_to_str/ftoa, bool_to_str
|
|
12
|
+
|
|
13
|
+
运行时约定:
|
|
14
|
+
- 所有值均为 64 位槽: int 为有符号整数; float 为 float64 位模式;
|
|
15
|
+
bool 为 0/1; string/struct/数组为内存指针。
|
|
16
|
+
- 浮点运算经 SYS 宿主调用 (FADD/FSUB/...), 数学函数同理。
|
|
17
|
+
- 栈帧: [参数...][返回地址][局部变量/数组...] , SP 指向帧内最低地址。
|
|
18
|
+
- struct 采用浅拷贝语义 (变量保存对象指针, 堆分配, 不回收)。
|
|
19
|
+
- 定长数组就地存放 (数据段/栈帧); int[][] 为指向行指针数组的指针。
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
import re
|
|
24
|
+
import struct
|
|
25
|
+
from dataclasses import dataclass, field
|
|
26
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
27
|
+
|
|
28
|
+
from .console import Console
|
|
29
|
+
from .errors import CompilerError
|
|
30
|
+
from .isa import Syscall
|
|
31
|
+
|
|
32
|
+
# ---------------- 类型表示 ----------------
|
|
33
|
+
# 'int' / 'float' / 'bool' / 'string' / 'void'
|
|
34
|
+
# ('struct', Name)
|
|
35
|
+
# ('array', elem_type, size) 定长数组 (多维: elem 仍为 array)
|
|
36
|
+
# ('ptrarray', elem_type) 动态/参数数组 (int[] / int[][])
|
|
37
|
+
|
|
38
|
+
SCALARS = {'int', 'float', 'bool', 'string', 'void'}
|
|
39
|
+
|
|
40
|
+
Operand = Tuple[Any, ...]
|
|
41
|
+
Instruction = Tuple[str, List[Operand]]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _is_scalar(t) -> bool:
|
|
45
|
+
return isinstance(t, str)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _is_struct(t) -> bool:
|
|
49
|
+
return isinstance(t, tuple) and t[0] == 'struct'
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _is_fixed_array(t) -> bool:
|
|
53
|
+
return isinstance(t, tuple) and t[0] == 'array'
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _is_ptr_array(t) -> bool:
|
|
57
|
+
return isinstance(t, tuple) and t[0] == 'ptrarray'
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _array_elem(t):
|
|
61
|
+
return t[1]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _type_slots(t) -> int:
|
|
65
|
+
"""类型占据的 qword 槽数。"""
|
|
66
|
+
if _is_fixed_array(t):
|
|
67
|
+
elem, size = t[1], t[2]
|
|
68
|
+
return size * _type_slots(elem)
|
|
69
|
+
return 1 # 标量/struct指针/ptrarray 均为 1 槽
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ==================== 词法分析 ====================
|
|
73
|
+
|
|
74
|
+
_KEYWORDS = {
|
|
75
|
+
'struct', 'function', 'return', 'if', 'else', 'while', 'for', 'do',
|
|
76
|
+
'switch', 'case', 'default', 'break', 'continue', 'true', 'false',
|
|
77
|
+
'int', 'float', 'bool', 'string', 'void', 'char', 'short', 'long',
|
|
78
|
+
'unsigned',
|
|
79
|
+
'set', 'add', 'subtract', 'multiply', 'divide', 'increment', 'decrement',
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# 声明起始的标量类型词 (含新支持的类型别名, 均映射到 64 位槽 int 模型)
|
|
83
|
+
BASE_TYPE_WORDS = ('int', 'float', 'bool', 'string', 'char', 'short', 'long',
|
|
84
|
+
'unsigned')
|
|
85
|
+
|
|
86
|
+
# 复合赋值: 词法 token -> C 风格运算符
|
|
87
|
+
_COMPOUND_ASSIGN = {
|
|
88
|
+
'PLUSEQ': '+=', 'MINUSEQ': '-=', 'STAREQ': '*=',
|
|
89
|
+
'SLASHEQ': '/=', 'PERCENTEQ': '%=',
|
|
90
|
+
'ANDEQ': '&=', 'OREQ': '|=', 'XOREQ': '^=',
|
|
91
|
+
'SHLEQ': '<<=', 'SHREQ': '>>=',
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_SINGLE_OPS = {
|
|
95
|
+
'{': 'LBRACE', '}': 'RBRACE', '(': 'LPAREN', ')': 'RPAREN',
|
|
96
|
+
'[': 'LBRACKET', ']': 'RBRACKET', ',': 'COMMA', ';': 'SEMI',
|
|
97
|
+
'+': 'PLUS', '-': 'MINUS', '*': 'STAR', '/': 'SLASH', '%': 'PERCENT',
|
|
98
|
+
'=': 'ASSIGN', '<': 'LT', '>': 'GT', '!': 'BANG', '.': 'DOT',
|
|
99
|
+
'?': 'QUESTION', ':': 'COLON',
|
|
100
|
+
'&': 'AMP', '|': 'PIPE', '^': 'CARET', '~': 'TILDE',
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# 复合赋值运算符 -> 底层运算符
|
|
104
|
+
_COMPOUND_TO_BASE = {
|
|
105
|
+
'+=': '+', '-=': '-', '*=': '*', '/=': '/', '%=': '%',
|
|
106
|
+
'&=': '&', '|=': '|', '^=': '^', '<<=': '<<', '>>=': '>>',
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
# 宿主能力内建 (表驱动): 名称 -> (SYS 功能号, 参数个数, 返回类型)。
|
|
110
|
+
# 全部由 Go 原生引擎实现; 解释器 (--no-native) 下会给出明确错误。
|
|
111
|
+
HOST_BUILTINS = {
|
|
112
|
+
# 联网音频
|
|
113
|
+
'audio_play': (Syscall.AUDIOPLAY, 1, 'int'),
|
|
114
|
+
'audio_stop': (Syscall.AUDIOSTOP, 0, 'void'),
|
|
115
|
+
'audio_volume': (Syscall.AUDIOVOL, 1, 'void'),
|
|
116
|
+
'audio_wait': (Syscall.AUDIOWAIT, 0, 'void'),
|
|
117
|
+
# 2D 绘图画布
|
|
118
|
+
'canvas': (Syscall.CANVASNEW, 2, 'void'),
|
|
119
|
+
'set_color': (Syscall.CANVASSET, 1, 'void'),
|
|
120
|
+
'fill_rect': (Syscall.CANVASRECT, 4, 'void'),
|
|
121
|
+
'fill_circle': (Syscall.CANVASCIRC, 3, 'void'),
|
|
122
|
+
'draw_line': (Syscall.CANVASLINE, 4, 'void'),
|
|
123
|
+
'draw_text': (Syscall.CANVASTEXT, 3, 'void'),
|
|
124
|
+
'save_png': (Syscall.CANVASSAVE, 1, 'int'),
|
|
125
|
+
'show_canvas': (Syscall.CANVASSHOW, 0, 'int'),
|
|
126
|
+
# 系统原生交互 (跨平台)
|
|
127
|
+
'file_read': (Syscall.FILEREAD, 1, 'string'),
|
|
128
|
+
'file_write': (Syscall.FILEWRITE, 2, 'int'),
|
|
129
|
+
'file_append': (Syscall.FILEAPPEND, 2, 'int'),
|
|
130
|
+
'file_exists': (Syscall.FILEEXISTS, 1, 'int'),
|
|
131
|
+
'file_delete': (Syscall.FILEDELETE, 1, 'int'),
|
|
132
|
+
'file_size': (Syscall.FILESIZE, 1, 'int'),
|
|
133
|
+
'mkdir': (Syscall.MKDIR, 1, 'int'),
|
|
134
|
+
'dir_list': (Syscall.DIRLIST, 1, 'string'),
|
|
135
|
+
'exec': (Syscall.EXEC, 1, 'int'),
|
|
136
|
+
'exec_output': (Syscall.EXECOUTPUT, 1, 'string'),
|
|
137
|
+
'getenv': (Syscall.GETENV, 1, 'string'),
|
|
138
|
+
'setenv': (Syscall.SETENV, 2, 'int'),
|
|
139
|
+
'os_name': (Syscall.OSNAME, 0, 'string'),
|
|
140
|
+
'hostname': (Syscall.HOSTNAME, 0, 'string'),
|
|
141
|
+
'username': (Syscall.USERNAME, 0, 'string'),
|
|
142
|
+
'cwd': (Syscall.CWD, 0, 'string'),
|
|
143
|
+
'home_dir': (Syscall.HOMEDIR, 0, 'string'),
|
|
144
|
+
# Termux API
|
|
145
|
+
'termux_available': (Syscall.TERMUXAVAIL, 0, 'int'),
|
|
146
|
+
'termux_notify': (Syscall.TERMUXNOTIFY, 2, 'int'),
|
|
147
|
+
'termux_toast': (Syscall.TERMUXTOAST, 1, 'int'),
|
|
148
|
+
'termux_clipboard_get': (Syscall.TERMUXCLIPGET, 0, 'string'),
|
|
149
|
+
'termux_clipboard_set': (Syscall.TERMUXCLIPSET, 1, 'int'),
|
|
150
|
+
'termux_battery': (Syscall.TERMUXBATTERY, 0, 'string'),
|
|
151
|
+
'termux_vibrate': (Syscall.TERMUXVIBRATE, 1, 'int'),
|
|
152
|
+
'termux_tts': (Syscall.TERMUXTTS, 1, 'int'),
|
|
153
|
+
'termux_location': (Syscall.TERMUXLOCATION, 0, 'string'),
|
|
154
|
+
'termux_wifi_info': (Syscall.TERMUXWIFI, 0, 'string'),
|
|
155
|
+
'termux_dialog': (Syscall.TERMUXDIALOG, 1, 'string'),
|
|
156
|
+
'termux_sms_send': (Syscall.TERMUXSMS, 2, 'int'),
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# 内建函数最少参数个数 (按各分支实际索引的最大下标 + 1 得出)。
|
|
160
|
+
# 缺失参数旧代码会直接 IndexError 崩溃 (如 sqrt()、substr("a",1)),
|
|
161
|
+
# 现在统一报 CompilerError。必须与 Go 侧 compiler.builtinMinArgs 保持一致。
|
|
162
|
+
BUILTIN_MIN_ARGS = {
|
|
163
|
+
'println': 0, 'print': 0,
|
|
164
|
+
'sqrt': 1, 'sin': 1, 'cos': 1, 'tan': 1,
|
|
165
|
+
'floor': 1, 'ceil': 1, 'round': 1,
|
|
166
|
+
'min': 2, 'max': 2,
|
|
167
|
+
'idiv': 2, 'pow': 2,
|
|
168
|
+
'abs': 1, 'strlen': 1, 'strcmp': 2, 'strcpy': 1,
|
|
169
|
+
'rand': 0, 'srand': 1,
|
|
170
|
+
'int_to_str': 1, 'itoa': 1,
|
|
171
|
+
'float_to_str': 1, 'ftoa': 1,
|
|
172
|
+
'bool_to_str': 1,
|
|
173
|
+
'substr': 3, 'indexof': 2,
|
|
174
|
+
'upper': 1, 'lower': 1,
|
|
175
|
+
'trim': 1, 'ltrim': 1, 'rtrim': 1, 'atoi': 1,
|
|
176
|
+
'time': 0, 'input': 0,
|
|
177
|
+
}
|
|
178
|
+
BUILTIN_MIN_ARGS.update({k: v[1] for k, v in HOST_BUILTINS.items()})
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@dataclass
|
|
182
|
+
class Token:
|
|
183
|
+
kind: str
|
|
184
|
+
value: Any
|
|
185
|
+
line: int
|
|
186
|
+
filename: Optional[str] = None
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def tokenize(source: str,
|
|
190
|
+
origin: Optional[List[Optional[Tuple[str, int]]]] = None
|
|
191
|
+
) -> List[Token]:
|
|
192
|
+
tokens: List[Token] = []
|
|
193
|
+
i, line, n = 0, 1, len(source)
|
|
194
|
+
|
|
195
|
+
def at_loc(ln: int) -> str:
|
|
196
|
+
if origin and 0 < ln < len(origin):
|
|
197
|
+
ent = origin[ln]
|
|
198
|
+
if ent is not None:
|
|
199
|
+
f, lineno = ent
|
|
200
|
+
return f"{f}:{lineno}"
|
|
201
|
+
return f"line {ln}"
|
|
202
|
+
|
|
203
|
+
def skip_comment_block():
|
|
204
|
+
nonlocal i, line
|
|
205
|
+
i += 2
|
|
206
|
+
while i < n - 1 and not (source[i] == '*' and source[i + 1] == '/'):
|
|
207
|
+
if source[i] == '\n':
|
|
208
|
+
line += 1
|
|
209
|
+
i += 1
|
|
210
|
+
i += 2
|
|
211
|
+
|
|
212
|
+
while i < n:
|
|
213
|
+
c = source[i]
|
|
214
|
+
if c == '\n':
|
|
215
|
+
tokens.append(Token('NL', '\n', line))
|
|
216
|
+
line += 1
|
|
217
|
+
i += 1
|
|
218
|
+
elif c in ' \t\r\ufeff':
|
|
219
|
+
i += 1
|
|
220
|
+
elif c == '/' and i + 1 < n and source[i + 1] == '/':
|
|
221
|
+
while i < n and source[i] != '\n':
|
|
222
|
+
i += 1
|
|
223
|
+
elif c == '/' and i + 1 < n and source[i + 1] == '*':
|
|
224
|
+
skip_comment_block()
|
|
225
|
+
elif c == '"':
|
|
226
|
+
start_line = line
|
|
227
|
+
i += 1
|
|
228
|
+
buf = []
|
|
229
|
+
while i < n and source[i] != '"':
|
|
230
|
+
if source[i] == '\\' and i + 1 < n:
|
|
231
|
+
esc = source[i + 1]
|
|
232
|
+
buf.append({'n': '\n', 't': '\t', 'r': '\r',
|
|
233
|
+
'"': '"', '\\': '\\', '0': '\0'}.get(esc, esc))
|
|
234
|
+
i += 2
|
|
235
|
+
else:
|
|
236
|
+
if source[i] == '\n':
|
|
237
|
+
line += 1
|
|
238
|
+
buf.append(source[i])
|
|
239
|
+
i += 1
|
|
240
|
+
i += 1
|
|
241
|
+
tokens.append(Token('STRING', ''.join(buf), start_line))
|
|
242
|
+
elif c.isdigit() or (c == '.' and i + 1 < n and source[i + 1].isdigit()):
|
|
243
|
+
start = i
|
|
244
|
+
is_float = False
|
|
245
|
+
if c == '0' and i + 1 < n and source[i + 1] in 'xXbBoO':
|
|
246
|
+
# 进制前缀: 0x/0X 16, 0b/0B 2, 0o/0O 8
|
|
247
|
+
base = {'x': 16, 'X': 16, 'b': 2, 'B': 2,
|
|
248
|
+
'o': 8, 'O': 8}[source[i + 1]]
|
|
249
|
+
i += 2
|
|
250
|
+
dstart = i
|
|
251
|
+
allowed = ('0123456789abcdefABCDEF_' if base == 16 else
|
|
252
|
+
('01_' if base == 2 else '01234567_'))
|
|
253
|
+
while i < n and source[i] in allowed:
|
|
254
|
+
i += 1
|
|
255
|
+
if i == dstart or not any(ch != '_' for ch in
|
|
256
|
+
source[dstart:i]):
|
|
257
|
+
raise CompilerError(f"Malformed numeric literal at "
|
|
258
|
+
f"{at_loc(line)}")
|
|
259
|
+
dend = i
|
|
260
|
+
# 后缀 (u/U/l/L, f/F): 64 位槽模型忽略宽度差异。
|
|
261
|
+
# 注意: 数值文本必须在吃后缀"之前"截取, 否则 0xFFu 会整段
|
|
262
|
+
# 交给 int() 而抛裸 ValueError。
|
|
263
|
+
while i < n and source[i] in 'uUlL':
|
|
264
|
+
i += 1
|
|
265
|
+
if i < n and source[i] in 'fF':
|
|
266
|
+
is_float = True
|
|
267
|
+
i += 1
|
|
268
|
+
text = source[start:dend]
|
|
269
|
+
norm = '0' + text[1].lower() + text[2:]
|
|
270
|
+
try:
|
|
271
|
+
value = int(norm.replace('_', ''), 0)
|
|
272
|
+
except ValueError:
|
|
273
|
+
raise CompilerError(f"Malformed numeric literal at "
|
|
274
|
+
f"{at_loc(line)}") from None
|
|
275
|
+
if value > 0xFFFFFFFFFFFFFFFF:
|
|
276
|
+
raise CompilerError(
|
|
277
|
+
f"Numeric literal out of 64-bit range at "
|
|
278
|
+
f"{at_loc(line)}")
|
|
279
|
+
else:
|
|
280
|
+
while i < n and (source[i].isdigit() or source[i] == '.'
|
|
281
|
+
or source[i] == '_'):
|
|
282
|
+
if source[i] == '.':
|
|
283
|
+
is_float = True
|
|
284
|
+
i += 1
|
|
285
|
+
if i < n and source[i] in 'eE':
|
|
286
|
+
is_float = True
|
|
287
|
+
i += 1
|
|
288
|
+
if i < n and source[i] in '+-':
|
|
289
|
+
i += 1
|
|
290
|
+
while i < n and (source[i].isdigit() or source[i] == '_'):
|
|
291
|
+
i += 1
|
|
292
|
+
dend = i
|
|
293
|
+
# 同上: 先截取数值文本, 再吃后缀
|
|
294
|
+
while i < n and source[i] in 'uUlL':
|
|
295
|
+
i += 1
|
|
296
|
+
if i < n and source[i] in 'fF':
|
|
297
|
+
is_float = True
|
|
298
|
+
i += 1
|
|
299
|
+
text = source[start:dend].replace('_', '')
|
|
300
|
+
try:
|
|
301
|
+
value = float(text) if is_float else int(text)
|
|
302
|
+
except ValueError:
|
|
303
|
+
raise CompilerError(f"Malformed numeric literal at "
|
|
304
|
+
f"{at_loc(line)}") from None
|
|
305
|
+
if not is_float and value > 0x7FFFFFFFFFFFFFFF:
|
|
306
|
+
raise CompilerError(
|
|
307
|
+
f"Numeric literal out of 64-bit range at "
|
|
308
|
+
f"{at_loc(line)}")
|
|
309
|
+
tokens.append(Token('FLOAT', float(value), line) if is_float
|
|
310
|
+
else Token('NUMBER', int(value), line))
|
|
311
|
+
elif c.isalpha() or c == '_':
|
|
312
|
+
start = i
|
|
313
|
+
while i < n and (source[i].isalnum() or source[i] == '_'):
|
|
314
|
+
i += 1
|
|
315
|
+
word = source[start:i]
|
|
316
|
+
tokens.append(Token('IDENT', word, line))
|
|
317
|
+
elif c == '-' and i + 1 < n and source[i + 1] == '>':
|
|
318
|
+
tokens.append(Token('ARROW', '->', line))
|
|
319
|
+
i += 2
|
|
320
|
+
elif c == "'": # 字符字面量: 'a' '\n' '\'' ...
|
|
321
|
+
start_line = line
|
|
322
|
+
i += 1
|
|
323
|
+
if i >= n:
|
|
324
|
+
raise CompilerError(f"Unterminated char literal at "
|
|
325
|
+
f"{at_loc(start_line)}")
|
|
326
|
+
if source[i] == '\\' and i + 1 < n:
|
|
327
|
+
esc = source[i + 1]
|
|
328
|
+
val = {'n': 10, 't': 9, 'r': 13, '0': 0, 'a': 7, 'b': 8,
|
|
329
|
+
'f': 12, 'v': 11, "'": 39, '"': 34,
|
|
330
|
+
'\\': 92}.get(esc, ord(esc))
|
|
331
|
+
i += 2
|
|
332
|
+
else:
|
|
333
|
+
val = ord(source[i])
|
|
334
|
+
i += 1
|
|
335
|
+
if i >= n or source[i] != "'":
|
|
336
|
+
raise CompilerError(f"Unterminated char literal at "
|
|
337
|
+
f"{at_loc(start_line)}")
|
|
338
|
+
i += 1
|
|
339
|
+
tokens.append(Token('NUMBER', val, line))
|
|
340
|
+
elif c in ('+', '-', '*', '/', '%') and i + 1 < n and source[i + 1] == '=':
|
|
341
|
+
kind = {'+': 'PLUSEQ', '-': 'MINUSEQ', '*': 'STAREQ',
|
|
342
|
+
'/': 'SLASHEQ', '%': 'PERCENTEQ'}[c]
|
|
343
|
+
tokens.append(Token(kind, c + '=', line))
|
|
344
|
+
i += 2
|
|
345
|
+
elif c in ('&', '|', '^') and i + 1 < n and source[i + 1] == '=':
|
|
346
|
+
kind = {'&': 'ANDEQ', '|': 'OREQ', '^': 'XOREQ'}[c]
|
|
347
|
+
tokens.append(Token(kind, c + '=', line))
|
|
348
|
+
i += 2
|
|
349
|
+
elif c in ('<', '>') and i + 2 < n and source[i + 1] == c \
|
|
350
|
+
and source[i + 2] == '=':
|
|
351
|
+
tokens.append(Token('SHLEQ' if c == '<' else 'SHREQ',
|
|
352
|
+
c + c + '=', line))
|
|
353
|
+
i += 3
|
|
354
|
+
elif c in ('<', '>') and i + 1 < n and source[i + 1] == c:
|
|
355
|
+
tokens.append(Token('SHL' if c == '<' else 'SHR', c + c, line))
|
|
356
|
+
i += 2
|
|
357
|
+
elif c == '+' and i + 1 < n and source[i + 1] == '+':
|
|
358
|
+
tokens.append(Token('INC', '++', line))
|
|
359
|
+
i += 2
|
|
360
|
+
elif c == '-' and i + 1 < n and source[i + 1] == '-':
|
|
361
|
+
tokens.append(Token('DEC', '--', line))
|
|
362
|
+
i += 2
|
|
363
|
+
elif c == '=' and i + 1 < n and source[i + 1] == '=':
|
|
364
|
+
tokens.append(Token('EQ', '==', line))
|
|
365
|
+
i += 2
|
|
366
|
+
elif c == '!' and i + 1 < n and source[i + 1] == '=':
|
|
367
|
+
tokens.append(Token('NEQ', '!=', line))
|
|
368
|
+
i += 2
|
|
369
|
+
elif c == '<' and i + 1 < n and source[i + 1] == '=':
|
|
370
|
+
tokens.append(Token('LE', '<=', line))
|
|
371
|
+
i += 2
|
|
372
|
+
elif c == '>' and i + 1 < n and source[i + 1] == '=':
|
|
373
|
+
tokens.append(Token('GE', '>=', line))
|
|
374
|
+
i += 2
|
|
375
|
+
elif c == '&' and i + 1 < n and source[i + 1] == '&':
|
|
376
|
+
tokens.append(Token('AND', '&&', line))
|
|
377
|
+
i += 2
|
|
378
|
+
elif c == '|' and i + 1 < n and source[i + 1] == '|':
|
|
379
|
+
tokens.append(Token('OR', '||', line))
|
|
380
|
+
i += 2
|
|
381
|
+
elif c in _SINGLE_OPS:
|
|
382
|
+
tokens.append(Token(_SINGLE_OPS[c], c, line))
|
|
383
|
+
i += 1
|
|
384
|
+
else:
|
|
385
|
+
raise CompilerError(f"Unexpected character {c!r} at {at_loc(line)}")
|
|
386
|
+
|
|
387
|
+
# 行连接: 圆/方括号深度内或行尾为运算符时 NL 无效;
|
|
388
|
+
# 花括号 {} 块内的 NL 必须保留 (语句以换行终止)
|
|
389
|
+
filtered: List[Token] = []
|
|
390
|
+
depth = 0
|
|
391
|
+
open_kw = {'LPAREN', 'LBRACKET'}
|
|
392
|
+
close_kw = {'RPAREN', 'RBRACKET'}
|
|
393
|
+
continue_ops = {'PLUS', 'MINUS', 'STAR', 'SLASH', 'PERCENT', 'ASSIGN',
|
|
394
|
+
'LT', 'GT', 'LE', 'GE', 'EQ', 'NEQ', 'AND', 'OR', 'COMMA',
|
|
395
|
+
'ARROW', 'DOT', 'PLUSEQ', 'MINUSEQ', 'STAREQ', 'SLASHEQ',
|
|
396
|
+
'PERCENTEQ', 'INC', 'DEC',
|
|
397
|
+
'AMP', 'PIPE', 'CARET', 'TILDE', 'SHL', 'SHR',
|
|
398
|
+
'ANDEQ', 'OREQ', 'XOREQ', 'SHLEQ', 'SHREQ'}
|
|
399
|
+
for tok in tokens:
|
|
400
|
+
if tok.kind in open_kw:
|
|
401
|
+
depth += 1
|
|
402
|
+
elif tok.kind in close_kw:
|
|
403
|
+
depth = max(0, depth - 1)
|
|
404
|
+
if tok.kind == 'NL':
|
|
405
|
+
if depth > 0:
|
|
406
|
+
continue
|
|
407
|
+
prev = filtered[-1] if filtered else None
|
|
408
|
+
if prev is not None and prev.kind in continue_ops:
|
|
409
|
+
continue
|
|
410
|
+
if filtered and filtered[-1].kind == 'NL':
|
|
411
|
+
continue
|
|
412
|
+
filtered.append(tok)
|
|
413
|
+
filtered.append(Token('EOF', None, line))
|
|
414
|
+
return filtered
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
# ==================== import 预处理 (B2) ====================
|
|
418
|
+
# import "path.cin" 仅在文件顶部/列首识别; 相对源文件目录或仓库 lib/ 目录解析;
|
|
419
|
+
# 同一文件每个编译仅包含一次, 循环引用报错。
|
|
420
|
+
|
|
421
|
+
_IMPORT_RE = re.compile(r'^import\s+["\']([^"\']+)["\']\s*;?\s*$')
|
|
422
|
+
|
|
423
|
+
_CODECIN_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _resolve_import(name: str, source_dir: str, lib_dir: str) -> str:
|
|
427
|
+
candidates = [os.path.join(source_dir, name),
|
|
428
|
+
os.path.join(lib_dir, name) if lib_dir else '',
|
|
429
|
+
os.path.join(_CODECIN_ROOT, name)]
|
|
430
|
+
for cand in candidates:
|
|
431
|
+
if cand and os.path.isfile(cand):
|
|
432
|
+
return cand
|
|
433
|
+
raise CompilerError(f"Import file not found: {name!r} (searched "
|
|
434
|
+
f"{source_dir}, {lib_dir}, {_CODECIN_ROOT})")
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def _collect_module_lines(path: str, loaded: set, active: set,
|
|
438
|
+
out: List[Tuple[str, str]]) -> None:
|
|
439
|
+
"""深度优先收集 (源文件, 文本行) 序列 (import 处内联展开)。
|
|
440
|
+
|
|
441
|
+
防重复: 每个 realpath 每编译一次仅包含一次; 循环引用报错。
|
|
442
|
+
"""
|
|
443
|
+
real = os.path.realpath(os.path.abspath(path))
|
|
444
|
+
if real in active:
|
|
445
|
+
raise CompilerError(f"Circular import: {path} ({real})")
|
|
446
|
+
if real in loaded:
|
|
447
|
+
return
|
|
448
|
+
active.add(real)
|
|
449
|
+
with open(real, encoding='utf-8-sig') as f:
|
|
450
|
+
# utf-8-sig: 容忍 Windows 编辑器写出的 BOM, 否则首行 `import ...`
|
|
451
|
+
# 匹配不上 _IMPORT_RE, 会报一个与真实原因无关的解析错误
|
|
452
|
+
lines = f.read().split('\n')
|
|
453
|
+
for line in lines:
|
|
454
|
+
m = _IMPORT_RE.match(line)
|
|
455
|
+
if m:
|
|
456
|
+
target = _resolve_import(
|
|
457
|
+
m.group(1), os.path.dirname(real),
|
|
458
|
+
os.path.join(_CODECIN_ROOT, 'lib'))
|
|
459
|
+
_collect_module_lines(target, loaded, active, out)
|
|
460
|
+
continue
|
|
461
|
+
out.append((real, line))
|
|
462
|
+
active.discard(real)
|
|
463
|
+
loaded.add(real)
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def load_program_source_mapped(path: str) -> Tuple[str, List[Optional[Tuple[str, int]]]]:
|
|
467
|
+
"""读取 CIN 并展开 import, 返回 (文本, 行来源表)。
|
|
468
|
+
|
|
469
|
+
origin[merged_line] = (源文件 realpath, 源文件内行号); origin[0] = None。
|
|
470
|
+
"""
|
|
471
|
+
real = os.path.realpath(os.path.abspath(path))
|
|
472
|
+
out: List[Tuple[str, str]] = []
|
|
473
|
+
_collect_module_lines(real, set(), set(), out)
|
|
474
|
+
counters: Dict[str, int] = {}
|
|
475
|
+
origin: List[Optional[Tuple[str, int]]] = [None]
|
|
476
|
+
for fname, _line in out:
|
|
477
|
+
counters[fname] = counters.get(fname, 0) + 1
|
|
478
|
+
origin.append((fname, counters[fname]))
|
|
479
|
+
text = '\n'.join(line for _f, line in out)
|
|
480
|
+
return text, origin
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def load_program_source(path: str) -> str:
|
|
484
|
+
"""读取 CIN 文件并展开 import (返回可直接 tokenize 的源码文本)。"""
|
|
485
|
+
text, _origin = load_program_source_mapped(path)
|
|
486
|
+
return text
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def _remap_tokens(tokens: List[Token], origin: List[Optional[Tuple[str, int]]]
|
|
490
|
+
) -> None:
|
|
491
|
+
"""把拼合文本中的 token 行号重定位到源文件 (file, line)。"""
|
|
492
|
+
for tok in tokens:
|
|
493
|
+
if 0 < tok.line < len(origin):
|
|
494
|
+
ent = origin[tok.line]
|
|
495
|
+
if ent is not None:
|
|
496
|
+
tok.filename, tok.line = ent[0], ent[1]
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
# ==================== 语法分析 ====================
|
|
500
|
+
|
|
501
|
+
@dataclass
|
|
502
|
+
class StructDef:
|
|
503
|
+
name: str
|
|
504
|
+
fields: List[Tuple[str, Any]] = field(default_factory=list) # (name, type)
|
|
505
|
+
offsets: Dict[str, int] = field(default_factory=dict) # qword 偏移
|
|
506
|
+
size_slots: int = 0
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
@dataclass
|
|
510
|
+
class FuncDef:
|
|
511
|
+
name: str
|
|
512
|
+
params: List[Tuple[str, Any]]
|
|
513
|
+
ret_type: Any
|
|
514
|
+
body: list
|
|
515
|
+
line: int
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
@dataclass
|
|
519
|
+
class GlobalVar:
|
|
520
|
+
name: str
|
|
521
|
+
vtype: Any
|
|
522
|
+
addr: int
|
|
523
|
+
init: Optional[list] = None # AST 表达式
|
|
524
|
+
array_lit: Optional[list] = None # 数组字面量行
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
class Parser:
|
|
528
|
+
def __init__(self, tokens: List[Token]):
|
|
529
|
+
self.toks = tokens
|
|
530
|
+
self.pos = 0
|
|
531
|
+
|
|
532
|
+
def peek(self, k: int = 0) -> Token:
|
|
533
|
+
return self.toks[min(self.pos + k, len(self.toks) - 1)]
|
|
534
|
+
|
|
535
|
+
def next(self) -> Token:
|
|
536
|
+
t = self.toks[self.pos]
|
|
537
|
+
self.pos += 1
|
|
538
|
+
return t
|
|
539
|
+
|
|
540
|
+
def accept(self, kind: str) -> Optional[Token]:
|
|
541
|
+
if self.peek().kind == kind:
|
|
542
|
+
return self.next()
|
|
543
|
+
return None
|
|
544
|
+
|
|
545
|
+
def expect(self, kind: str) -> Token:
|
|
546
|
+
t = self.peek()
|
|
547
|
+
if t.kind != kind:
|
|
548
|
+
raise CompilerError(f"Expected {kind} but got {t.kind} ({t.value!r}) "
|
|
549
|
+
f"at {self._loc(t)}")
|
|
550
|
+
return self.next()
|
|
551
|
+
|
|
552
|
+
def skip_nl(self) -> None:
|
|
553
|
+
while self.accept('NL'):
|
|
554
|
+
pass
|
|
555
|
+
|
|
556
|
+
def _loc(self, tok: Optional[Token] = None) -> str:
|
|
557
|
+
"""token 的 'file:line' 定位 (import 展开后为真实源文件)。"""
|
|
558
|
+
t = tok if tok is not None else self.peek()
|
|
559
|
+
return f"{t.filename or '<cin>'}:{t.line}"
|
|
560
|
+
|
|
561
|
+
# ---------------- 类型 ----------------
|
|
562
|
+
|
|
563
|
+
def parse_type(self) -> Any:
|
|
564
|
+
t = self.expect('IDENT')
|
|
565
|
+
base = t.value
|
|
566
|
+
if base == 'unsigned':
|
|
567
|
+
# unsigned [char|short|int|long]; 缺省为 int
|
|
568
|
+
nxt = self.peek()
|
|
569
|
+
if nxt.kind == 'IDENT' and nxt.value in ('char', 'short', 'int', 'long'):
|
|
570
|
+
self.next()
|
|
571
|
+
vtype = 'int'
|
|
572
|
+
elif base in ('int', 'float', 'bool', 'string', 'void', 'char', 'short',
|
|
573
|
+
'long'):
|
|
574
|
+
# char/short/long 为整数别名 (64 位槽模型, 与 int 同宽)
|
|
575
|
+
vtype = 'int' if base in ('char', 'short', 'long') else base
|
|
576
|
+
else:
|
|
577
|
+
vtype = ('struct', base)
|
|
578
|
+
# int[] / int[][] 形式 (后缀在类型名上)
|
|
579
|
+
while self.peek().kind == 'LBRACKET' and self.peek(1).kind == 'RBRACKET':
|
|
580
|
+
self.next()
|
|
581
|
+
self.next()
|
|
582
|
+
vtype = ('ptrarray', vtype)
|
|
583
|
+
return vtype
|
|
584
|
+
|
|
585
|
+
def _is_decl_start(self) -> bool:
|
|
586
|
+
"""当前是否处于类型声明起始 (基础类型 / unsigned / struct 类型名)。"""
|
|
587
|
+
t = self.peek()
|
|
588
|
+
if t.kind != 'IDENT':
|
|
589
|
+
return False
|
|
590
|
+
v = t.value
|
|
591
|
+
if v in BASE_TYPE_WORDS:
|
|
592
|
+
return True
|
|
593
|
+
# struct 类型名 (裸标识符) 后跟另一个标识符 = 声明
|
|
594
|
+
return v not in _KEYWORDS and self.peek(1).kind == 'IDENT'
|
|
595
|
+
|
|
596
|
+
def parse_dims(self) -> List[int]:
|
|
597
|
+
dims = []
|
|
598
|
+
while self.peek().kind == 'LBRACKET':
|
|
599
|
+
self.next()
|
|
600
|
+
num = self.accept('NUMBER')
|
|
601
|
+
self.expect('RBRACKET')
|
|
602
|
+
dims.append(num.value if num else 0)
|
|
603
|
+
return dims
|
|
604
|
+
|
|
605
|
+
# ---------------- 程序 ----------------
|
|
606
|
+
|
|
607
|
+
def parse_program(self):
|
|
608
|
+
structs: Dict[str, StructDef] = {}
|
|
609
|
+
globals_: List[GlobalVar] = []
|
|
610
|
+
functions: Dict[str, FuncDef] = {}
|
|
611
|
+
|
|
612
|
+
self.skip_nl()
|
|
613
|
+
while self.peek().kind != 'EOF':
|
|
614
|
+
if self.peek().kind == 'IDENT' and self.peek().value == 'struct':
|
|
615
|
+
self._parse_struct(structs)
|
|
616
|
+
elif self.peek().kind == 'IDENT' and self.peek().value == 'function':
|
|
617
|
+
f = self._parse_function()
|
|
618
|
+
functions[f.name] = f
|
|
619
|
+
else:
|
|
620
|
+
self._parse_global(globals_)
|
|
621
|
+
self.skip_nl()
|
|
622
|
+
return structs, globals_, functions
|
|
623
|
+
|
|
624
|
+
def _parse_struct(self, structs: Dict[str, StructDef]) -> None:
|
|
625
|
+
self.next() # struct
|
|
626
|
+
name = self.expect('IDENT').value
|
|
627
|
+
self.expect('LBRACE')
|
|
628
|
+
self.skip_nl()
|
|
629
|
+
sd = StructDef(name=name)
|
|
630
|
+
off = 0
|
|
631
|
+
while self.peek().kind != 'RBRACE':
|
|
632
|
+
ftype = self.parse_type()
|
|
633
|
+
fname = self.expect('IDENT').value
|
|
634
|
+
dims = self.parse_dims()
|
|
635
|
+
t = ftype
|
|
636
|
+
for d in reversed(dims):
|
|
637
|
+
t = ('array', t, d) if d else ('ptrarray', t)
|
|
638
|
+
sd.fields.append((fname, t))
|
|
639
|
+
sd.offsets[fname] = off
|
|
640
|
+
off += _type_slots(t)
|
|
641
|
+
self.accept('SEMI')
|
|
642
|
+
self.skip_nl()
|
|
643
|
+
self.expect('RBRACE')
|
|
644
|
+
sd.size_slots = off
|
|
645
|
+
structs[name] = sd
|
|
646
|
+
self.accept('SEMI')
|
|
647
|
+
|
|
648
|
+
def _parse_function(self) -> FuncDef:
|
|
649
|
+
line = self.next().line # function
|
|
650
|
+
name = self.expect('IDENT').value
|
|
651
|
+
self.expect('LPAREN')
|
|
652
|
+
params: List[Tuple[str, Any]] = []
|
|
653
|
+
while self.peek().kind != 'RPAREN':
|
|
654
|
+
ptype = self.parse_type()
|
|
655
|
+
pname = self.expect('IDENT').value
|
|
656
|
+
dims = self.parse_dims()
|
|
657
|
+
for d in reversed(dims):
|
|
658
|
+
ptype = ('array', ptype, d) if d else ('ptrarray', ptype)
|
|
659
|
+
params.append((pname, ptype))
|
|
660
|
+
if not self.accept('COMMA'):
|
|
661
|
+
break
|
|
662
|
+
self.expect('RPAREN')
|
|
663
|
+
ret_type: Any = 'void'
|
|
664
|
+
if self.accept('ARROW'):
|
|
665
|
+
ret_type = self.parse_type()
|
|
666
|
+
self.expect('LBRACE')
|
|
667
|
+
body = self.parse_block_body(RBRACE_TOKENS)
|
|
668
|
+
self.expect('RBRACE')
|
|
669
|
+
return FuncDef(name, params, ret_type, body, line)
|
|
670
|
+
|
|
671
|
+
def _parse_global(self, globals_: List[GlobalVar]) -> None:
|
|
672
|
+
vtype = self.parse_type()
|
|
673
|
+
while True:
|
|
674
|
+
name = self.expect('IDENT').value
|
|
675
|
+
dims = self.parse_dims()
|
|
676
|
+
t = vtype
|
|
677
|
+
for d in reversed(dims):
|
|
678
|
+
t = ('array', t, d) if d else ('ptrarray', t)
|
|
679
|
+
gv = GlobalVar(name=name, vtype=t, addr=0)
|
|
680
|
+
if self.accept('ASSIGN'):
|
|
681
|
+
if self.peek().kind == 'LBRACE':
|
|
682
|
+
gv.array_lit = self.parse_array_literal()
|
|
683
|
+
else:
|
|
684
|
+
gv.init = self.parse_expr()
|
|
685
|
+
globals_.append(gv)
|
|
686
|
+
if not self.accept('COMMA'):
|
|
687
|
+
break
|
|
688
|
+
self.accept('SEMI')
|
|
689
|
+
|
|
690
|
+
def parse_array_literal(self) -> list:
|
|
691
|
+
self.expect('LBRACE')
|
|
692
|
+
rows: list = []
|
|
693
|
+
current: list = []
|
|
694
|
+
while self.peek().kind != 'RBRACE':
|
|
695
|
+
if self.accept('LBRACE'):
|
|
696
|
+
inner = []
|
|
697
|
+
while self.peek().kind != 'RBRACE':
|
|
698
|
+
inner.append(self.parse_expr())
|
|
699
|
+
if not self.accept('COMMA'):
|
|
700
|
+
break
|
|
701
|
+
self.expect('RBRACE')
|
|
702
|
+
rows.append(inner)
|
|
703
|
+
else:
|
|
704
|
+
current.append(self.parse_expr())
|
|
705
|
+
if not self.accept('COMMA'):
|
|
706
|
+
break
|
|
707
|
+
self.expect('RBRACE')
|
|
708
|
+
return rows if rows else current
|
|
709
|
+
|
|
710
|
+
# ---------------- 语句 ----------------
|
|
711
|
+
|
|
712
|
+
def parse_block_body(self, _unused=None) -> list:
|
|
713
|
+
stmts = []
|
|
714
|
+
self.skip_nl()
|
|
715
|
+
while self.peek().kind not in ('RBRACE', 'EOF'):
|
|
716
|
+
stmts.append(self.parse_stmt())
|
|
717
|
+
self.skip_nl()
|
|
718
|
+
return stmts
|
|
719
|
+
|
|
720
|
+
def parse_stmt(self):
|
|
721
|
+
t = self.peek()
|
|
722
|
+
if t.kind == 'LBRACE':
|
|
723
|
+
self.next()
|
|
724
|
+
body = self.parse_block_body()
|
|
725
|
+
self.expect('RBRACE')
|
|
726
|
+
return ('block', body)
|
|
727
|
+
if t.kind == 'IDENT' and t.value == 'assert':
|
|
728
|
+
return self.parse_assert()
|
|
729
|
+
if t.kind == 'IDENT' and t.value == 'return':
|
|
730
|
+
self.next()
|
|
731
|
+
expr = None if self.peek().kind in ('NL', 'SEMI', 'RBRACE') else self.parse_expr()
|
|
732
|
+
self.accept('SEMI')
|
|
733
|
+
return ('return', expr)
|
|
734
|
+
if t.kind == 'IDENT' and t.value == 'if':
|
|
735
|
+
return self.parse_if()
|
|
736
|
+
if t.kind == 'IDENT' and t.value == 'while':
|
|
737
|
+
self.next()
|
|
738
|
+
cond = self.parse_paren_expr()
|
|
739
|
+
body = self.parse_stmt()
|
|
740
|
+
return ('while', cond, body)
|
|
741
|
+
if t.kind == 'IDENT' and t.value == 'for':
|
|
742
|
+
return self.parse_for()
|
|
743
|
+
if t.kind == 'IDENT' and t.value == 'do':
|
|
744
|
+
return self.parse_do()
|
|
745
|
+
if t.kind == 'IDENT' and t.value == 'switch':
|
|
746
|
+
return self.parse_switch()
|
|
747
|
+
if t.kind == 'IDENT' and t.value == 'break':
|
|
748
|
+
self.next()
|
|
749
|
+
self.accept('SEMI')
|
|
750
|
+
return ('break',)
|
|
751
|
+
if t.kind == 'IDENT' and t.value == 'continue':
|
|
752
|
+
self.next()
|
|
753
|
+
self.accept('SEMI')
|
|
754
|
+
return ('continue',)
|
|
755
|
+
if self._is_decl_start():
|
|
756
|
+
return self.parse_decl()
|
|
757
|
+
if t.kind == 'IDENT' and t.value in ('set', 'add', 'subtract', 'multiply',
|
|
758
|
+
'divide', 'increment', 'decrement'):
|
|
759
|
+
return self.parse_cpu_stmt()
|
|
760
|
+
# 表达式语句 / 赋值
|
|
761
|
+
expr = self.parse_assign()
|
|
762
|
+
self.accept('SEMI')
|
|
763
|
+
return ('expr', expr)
|
|
764
|
+
|
|
765
|
+
def parse_assign(self):
|
|
766
|
+
target = self.parse_expr()
|
|
767
|
+
t = self.peek().kind
|
|
768
|
+
if t == 'ASSIGN':
|
|
769
|
+
self.next()
|
|
770
|
+
value = self.parse_assign()
|
|
771
|
+
return ('binop', '=', target, value)
|
|
772
|
+
if t in _COMPOUND_ASSIGN:
|
|
773
|
+
self.next()
|
|
774
|
+
value = self.parse_assign()
|
|
775
|
+
return ('binop', _COMPOUND_ASSIGN[t], target, value)
|
|
776
|
+
return target
|
|
777
|
+
|
|
778
|
+
def parse_do(self):
|
|
779
|
+
self.next() # do
|
|
780
|
+
body = self.parse_stmt()
|
|
781
|
+
self.skip_nl()
|
|
782
|
+
if not (self.peek().kind == 'IDENT' and self.peek().value == 'while'):
|
|
783
|
+
raise CompilerError("Expected 'while' after do body at "
|
|
784
|
+
f"{self._loc()}")
|
|
785
|
+
self.next()
|
|
786
|
+
cond = self.parse_paren_expr()
|
|
787
|
+
self.accept('SEMI')
|
|
788
|
+
return ('dowhile', body, cond)
|
|
789
|
+
|
|
790
|
+
def parse_switch(self):
|
|
791
|
+
self.next() # switch
|
|
792
|
+
cond = self.parse_paren_expr()
|
|
793
|
+
self.expect('LBRACE')
|
|
794
|
+
self.skip_nl()
|
|
795
|
+
# branches: [('case', const_expr|None, [stmt,...])] (None = default)
|
|
796
|
+
branches = []
|
|
797
|
+
cur: Optional[Tuple[Any, list]] = None
|
|
798
|
+
while self.peek().kind not in ('RBRACE', 'EOF'):
|
|
799
|
+
self.skip_nl()
|
|
800
|
+
t = self.peek()
|
|
801
|
+
if t.kind == 'IDENT' and t.value == 'case':
|
|
802
|
+
if cur is not None:
|
|
803
|
+
branches.append(cur)
|
|
804
|
+
self.next()
|
|
805
|
+
const = self.parse_expr()
|
|
806
|
+
self.expect('COLON')
|
|
807
|
+
cur = ('case', const, [])
|
|
808
|
+
elif t.kind == 'IDENT' and t.value == 'default':
|
|
809
|
+
if cur is not None:
|
|
810
|
+
branches.append(cur)
|
|
811
|
+
self.next()
|
|
812
|
+
self.expect('COLON')
|
|
813
|
+
cur = ('case', None, [])
|
|
814
|
+
else:
|
|
815
|
+
if cur is None:
|
|
816
|
+
raise CompilerError(
|
|
817
|
+
"Statement before first case in switch at "
|
|
818
|
+
f"{self._loc(t)}")
|
|
819
|
+
cur[2].append(self.parse_stmt())
|
|
820
|
+
self.skip_nl()
|
|
821
|
+
if cur is not None:
|
|
822
|
+
branches.append(cur)
|
|
823
|
+
self.expect('RBRACE')
|
|
824
|
+
if not branches:
|
|
825
|
+
raise CompilerError(f"Empty switch at {self._loc()}")
|
|
826
|
+
return ('switch', cond, branches)
|
|
827
|
+
|
|
828
|
+
def parse_assert(self):
|
|
829
|
+
tok = self.peek()
|
|
830
|
+
self.next() # assert
|
|
831
|
+
self.expect('LPAREN')
|
|
832
|
+
cond = self.parse_expr()
|
|
833
|
+
msg = None
|
|
834
|
+
if self.accept('COMMA'):
|
|
835
|
+
msg = self.parse_expr()
|
|
836
|
+
self.expect('RPAREN')
|
|
837
|
+
self.accept('SEMI')
|
|
838
|
+
return ('assert', cond, msg, tok.line, tok.filename)
|
|
839
|
+
|
|
840
|
+
def parse_if(self):
|
|
841
|
+
self.next()
|
|
842
|
+
cond = self.parse_paren_expr()
|
|
843
|
+
then_body = self.parse_stmt()
|
|
844
|
+
else_body = None
|
|
845
|
+
self.skip_nl()
|
|
846
|
+
if self.peek().kind == 'IDENT' and self.peek().value == 'else':
|
|
847
|
+
self.next()
|
|
848
|
+
self.skip_nl()
|
|
849
|
+
else_body = self.parse_stmt()
|
|
850
|
+
return ('if', cond, then_body, else_body)
|
|
851
|
+
|
|
852
|
+
def parse_for(self):
|
|
853
|
+
self.next() # for
|
|
854
|
+
self.expect('LPAREN')
|
|
855
|
+
# init
|
|
856
|
+
init = None
|
|
857
|
+
if self.peek().kind != 'SEMI':
|
|
858
|
+
if self._is_decl_start():
|
|
859
|
+
init = self.parse_decl(no_semi=True)
|
|
860
|
+
else:
|
|
861
|
+
init = ('expr', self.parse_expr())
|
|
862
|
+
self.expect('SEMI')
|
|
863
|
+
cond = None
|
|
864
|
+
if self.peek().kind != 'SEMI':
|
|
865
|
+
cond = self.parse_expr()
|
|
866
|
+
self.expect('SEMI')
|
|
867
|
+
update = None
|
|
868
|
+
if self.peek().kind != 'RPAREN':
|
|
869
|
+
update = ('expr', self.parse_assign())
|
|
870
|
+
self.expect('RPAREN')
|
|
871
|
+
body = self.parse_stmt()
|
|
872
|
+
return ('for', init, cond, update, body)
|
|
873
|
+
|
|
874
|
+
def parse_decl(self, no_semi: bool = False):
|
|
875
|
+
vtype = self.parse_type()
|
|
876
|
+
decls = []
|
|
877
|
+
while True:
|
|
878
|
+
name = self.expect('IDENT').value
|
|
879
|
+
dims = self.parse_dims()
|
|
880
|
+
t = vtype
|
|
881
|
+
for d in reversed(dims):
|
|
882
|
+
t = ('array', t, d) if d else ('ptrarray', t)
|
|
883
|
+
init = None
|
|
884
|
+
array_lit = None
|
|
885
|
+
if self.accept('ASSIGN'):
|
|
886
|
+
if self.peek().kind == 'LBRACE':
|
|
887
|
+
array_lit = self.parse_array_literal()
|
|
888
|
+
else:
|
|
889
|
+
init = self.parse_expr()
|
|
890
|
+
decls.append((name, t, init, array_lit))
|
|
891
|
+
if not self.accept('COMMA'):
|
|
892
|
+
break
|
|
893
|
+
if not no_semi:
|
|
894
|
+
self.accept('SEMI')
|
|
895
|
+
return ('decl', decls)
|
|
896
|
+
|
|
897
|
+
def parse_cpu_stmt(self):
|
|
898
|
+
op = self.next().value
|
|
899
|
+
operands = []
|
|
900
|
+
while self.peek().kind not in ('NL', 'SEMI', 'EOF'):
|
|
901
|
+
tok = self.next()
|
|
902
|
+
operands.append((tok.kind, tok.value))
|
|
903
|
+
self.accept('SEMI')
|
|
904
|
+
return ('cpu', op, operands)
|
|
905
|
+
|
|
906
|
+
def parse_paren_expr(self):
|
|
907
|
+
self.expect('LPAREN')
|
|
908
|
+
e = self.parse_expr()
|
|
909
|
+
self.expect('RPAREN')
|
|
910
|
+
return e
|
|
911
|
+
|
|
912
|
+
# ---------------- 表达式 ----------------
|
|
913
|
+
|
|
914
|
+
def parse_expr(self):
|
|
915
|
+
e = self.parse_or()
|
|
916
|
+
if self.accept('QUESTION'):
|
|
917
|
+
a = self.parse_assign()
|
|
918
|
+
self.expect('COLON')
|
|
919
|
+
b = self.parse_assign()
|
|
920
|
+
return ('cond', e, a, b)
|
|
921
|
+
return e
|
|
922
|
+
|
|
923
|
+
def parse_or(self):
|
|
924
|
+
left = self.parse_and()
|
|
925
|
+
while self.peek().kind == 'OR':
|
|
926
|
+
self.next()
|
|
927
|
+
right = self.parse_and()
|
|
928
|
+
left = ('binop', '||', left, right)
|
|
929
|
+
return left
|
|
930
|
+
|
|
931
|
+
def parse_and(self):
|
|
932
|
+
left = self.parse_bit_or()
|
|
933
|
+
while self.peek().kind == 'AND':
|
|
934
|
+
self.next()
|
|
935
|
+
right = self.parse_bit_or()
|
|
936
|
+
left = ('binop', '&&', left, right)
|
|
937
|
+
return left
|
|
938
|
+
|
|
939
|
+
def parse_bit_or(self):
|
|
940
|
+
left = self.parse_bit_xor()
|
|
941
|
+
while self.peek().kind == 'PIPE':
|
|
942
|
+
self.next()
|
|
943
|
+
right = self.parse_bit_xor()
|
|
944
|
+
left = ('binop', '|', left, right)
|
|
945
|
+
return left
|
|
946
|
+
|
|
947
|
+
def parse_bit_xor(self):
|
|
948
|
+
left = self.parse_bit_and()
|
|
949
|
+
while self.peek().kind == 'CARET':
|
|
950
|
+
self.next()
|
|
951
|
+
right = self.parse_bit_and()
|
|
952
|
+
left = ('binop', '^', left, right)
|
|
953
|
+
return left
|
|
954
|
+
|
|
955
|
+
def parse_bit_and(self):
|
|
956
|
+
left = self.parse_equality()
|
|
957
|
+
while self.peek().kind == 'AMP':
|
|
958
|
+
self.next()
|
|
959
|
+
right = self.parse_equality()
|
|
960
|
+
left = ('binop', '&', left, right)
|
|
961
|
+
return left
|
|
962
|
+
|
|
963
|
+
def parse_equality(self):
|
|
964
|
+
left = self.parse_relational()
|
|
965
|
+
while self.peek().kind in ('EQ', 'NEQ'):
|
|
966
|
+
op = '==' if self.next().kind == 'EQ' else '!='
|
|
967
|
+
right = self.parse_relational()
|
|
968
|
+
left = ('binop', op, left, right)
|
|
969
|
+
return left
|
|
970
|
+
|
|
971
|
+
def parse_relational(self):
|
|
972
|
+
left = self.parse_shift()
|
|
973
|
+
while self.peek().kind in ('LT', 'GT', 'LE', 'GE'):
|
|
974
|
+
tok = self.next()
|
|
975
|
+
op = {'LT': '<', 'GT': '>', 'LE': '<=', 'GE': '>='}[tok.kind]
|
|
976
|
+
right = self.parse_shift()
|
|
977
|
+
left = ('binop', op, left, right)
|
|
978
|
+
return left
|
|
979
|
+
|
|
980
|
+
def parse_shift(self):
|
|
981
|
+
left = self.parse_additive()
|
|
982
|
+
while self.peek().kind in ('SHL', 'SHR'):
|
|
983
|
+
op = '<<' if self.next().kind == 'SHL' else '>>'
|
|
984
|
+
right = self.parse_additive()
|
|
985
|
+
left = ('binop', op, left, right)
|
|
986
|
+
return left
|
|
987
|
+
|
|
988
|
+
def parse_additive(self):
|
|
989
|
+
left = self.parse_multiplicative()
|
|
990
|
+
while self.peek().kind in ('PLUS', 'MINUS'):
|
|
991
|
+
op = '+' if self.next().kind == 'PLUS' else '-'
|
|
992
|
+
right = self.parse_multiplicative()
|
|
993
|
+
left = ('binop', op, left, right)
|
|
994
|
+
return left
|
|
995
|
+
|
|
996
|
+
def parse_multiplicative(self):
|
|
997
|
+
left = self.parse_unary()
|
|
998
|
+
while self.peek().kind in ('STAR', 'SLASH', 'PERCENT'):
|
|
999
|
+
tok = self.next()
|
|
1000
|
+
op = {'STAR': '*', 'SLASH': '/', 'PERCENT': '%'}[tok.kind]
|
|
1001
|
+
right = self.parse_unary()
|
|
1002
|
+
left = ('binop', op, left, right)
|
|
1003
|
+
return left
|
|
1004
|
+
|
|
1005
|
+
def parse_unary(self):
|
|
1006
|
+
if self.peek().kind == 'BANG':
|
|
1007
|
+
self.next()
|
|
1008
|
+
return ('not', self.parse_unary())
|
|
1009
|
+
if self.peek().kind == 'TILDE':
|
|
1010
|
+
self.next()
|
|
1011
|
+
return ('bitnot', self.parse_unary())
|
|
1012
|
+
if self.peek().kind == 'MINUS':
|
|
1013
|
+
self.next()
|
|
1014
|
+
return ('neg', self.parse_unary())
|
|
1015
|
+
if self.peek().kind == 'INC':
|
|
1016
|
+
self.next()
|
|
1017
|
+
return ('preinc', self.parse_unary())
|
|
1018
|
+
if self.peek().kind == 'DEC':
|
|
1019
|
+
self.next()
|
|
1020
|
+
return ('predec', self.parse_unary())
|
|
1021
|
+
return self.parse_postfix()
|
|
1022
|
+
|
|
1023
|
+
def parse_postfix(self):
|
|
1024
|
+
e = self.parse_primary()
|
|
1025
|
+
while True:
|
|
1026
|
+
if self.peek().kind == 'LBRACKET':
|
|
1027
|
+
self.next()
|
|
1028
|
+
idx = self.parse_expr()
|
|
1029
|
+
self.expect('RBRACKET')
|
|
1030
|
+
e = ('index', e, idx)
|
|
1031
|
+
elif self.peek().kind == 'DOT':
|
|
1032
|
+
self.next()
|
|
1033
|
+
name = self.expect('IDENT').value
|
|
1034
|
+
e = ('member', e, name)
|
|
1035
|
+
elif self.peek().kind == 'INC':
|
|
1036
|
+
self.next()
|
|
1037
|
+
e = ('postinc', e)
|
|
1038
|
+
elif self.peek().kind == 'DEC':
|
|
1039
|
+
self.next()
|
|
1040
|
+
e = ('postdec', e)
|
|
1041
|
+
else:
|
|
1042
|
+
break
|
|
1043
|
+
return e
|
|
1044
|
+
|
|
1045
|
+
def parse_primary(self):
|
|
1046
|
+
t = self.peek()
|
|
1047
|
+
if t.kind == 'NUMBER':
|
|
1048
|
+
self.next()
|
|
1049
|
+
return ('num', t.value, False)
|
|
1050
|
+
if t.kind == 'FLOAT':
|
|
1051
|
+
self.next()
|
|
1052
|
+
return ('num', t.value, True)
|
|
1053
|
+
if t.kind == 'STRING':
|
|
1054
|
+
self.next()
|
|
1055
|
+
return ('str', t.value)
|
|
1056
|
+
if t.kind == 'IDENT' and t.value == 'true':
|
|
1057
|
+
self.next()
|
|
1058
|
+
return ('bool', True)
|
|
1059
|
+
if t.kind == 'IDENT' and t.value == 'false':
|
|
1060
|
+
self.next()
|
|
1061
|
+
return ('bool', False)
|
|
1062
|
+
if t.kind == 'LPAREN':
|
|
1063
|
+
return self.parse_paren_expr()
|
|
1064
|
+
if t.kind == 'IDENT':
|
|
1065
|
+
name = self.next().value
|
|
1066
|
+
if self.peek().kind == 'LPAREN':
|
|
1067
|
+
self.next()
|
|
1068
|
+
args = []
|
|
1069
|
+
while self.peek().kind != 'RPAREN':
|
|
1070
|
+
args.append(self.parse_expr())
|
|
1071
|
+
if not self.accept('COMMA'):
|
|
1072
|
+
break
|
|
1073
|
+
self.expect('RPAREN')
|
|
1074
|
+
return ('call', name, args)
|
|
1075
|
+
return ('var', name)
|
|
1076
|
+
raise CompilerError(f"Unexpected token {t.kind} ({t.value!r}) "
|
|
1077
|
+
f"at {self._loc(t)}")
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
RBRACE_TOKENS = None
|
|
1081
|
+
|
|
1082
|
+
|
|
1083
|
+
# ==================== 代码生成 ====================
|
|
1084
|
+
|
|
1085
|
+
class CompileResult:
|
|
1086
|
+
def __init__(self):
|
|
1087
|
+
self.instructions: List[Instruction] = []
|
|
1088
|
+
self.labels: Dict[str, int] = {}
|
|
1089
|
+
self.data_labels: Dict[str, int] = {}
|
|
1090
|
+
self.data_writes: List[Tuple[int, bytes]] = []
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
class CINCompiler:
|
|
1094
|
+
def __init__(self, console: Optional[Console] = None, logger=None):
|
|
1095
|
+
self.console = console or Console()
|
|
1096
|
+
self.logger = logger
|
|
1097
|
+
|
|
1098
|
+
def compile(self, filename: str, bounds_check: bool = False) -> CompileResult:
|
|
1099
|
+
source, origin = load_program_source_mapped(filename)
|
|
1100
|
+
return self.compile_source(source, filename,
|
|
1101
|
+
bounds_check=bounds_check, origin=origin)
|
|
1102
|
+
|
|
1103
|
+
def compile_source(self, source: str, filename: str = '<cin>',
|
|
1104
|
+
bounds_check: bool = False,
|
|
1105
|
+
origin: Optional[List[Optional[Tuple[str, int]]]] = None
|
|
1106
|
+
) -> CompileResult:
|
|
1107
|
+
dbg = self.logger.debug if (self.logger and self.logger.is_debug) \
|
|
1108
|
+
else (lambda msg: None)
|
|
1109
|
+
tokens = tokenize(source, origin)
|
|
1110
|
+
if origin:
|
|
1111
|
+
_remap_tokens(tokens, origin)
|
|
1112
|
+
dbg(f"CIN tokenize: {len(tokens)} tokens")
|
|
1113
|
+
parser = Parser(tokens)
|
|
1114
|
+
structs, globals_, functions = parser.parse_program()
|
|
1115
|
+
dbg(f"CIN parse: {len(structs)} structs, {len(globals_)} globals, "
|
|
1116
|
+
f"{len(functions)} functions "
|
|
1117
|
+
f"({', '.join(list(functions)[:8])}"
|
|
1118
|
+
f"{', ...' if len(functions) > 8 else ''})")
|
|
1119
|
+
for name, fn in functions.items():
|
|
1120
|
+
dbg(f"CIN function {name}: {len(fn.params)} params")
|
|
1121
|
+
|
|
1122
|
+
gen = CodeGen(structs, functions, filename=filename,
|
|
1123
|
+
bounds_check=bounds_check)
|
|
1124
|
+
gen.layout_globals(globals_)
|
|
1125
|
+
for name, (typ, addr, block) in gen.globals.items():
|
|
1126
|
+
dbg(f"CIN global '{name}': type={typ} addr=0x{addr:x} block={block}")
|
|
1127
|
+
result = gen.generate(globals_, functions)
|
|
1128
|
+
for name in functions:
|
|
1129
|
+
dbg(f"CIN codegen function '{name}' done")
|
|
1130
|
+
dbg(f"CIN codegen total: {len(result.instructions)} instructions, "
|
|
1131
|
+
f"{sum(len(d) for _, d in result.data_writes)} data bytes, "
|
|
1132
|
+
f"{len(result.labels)} labels, {len(result.data_writes)} data writes")
|
|
1133
|
+
return result
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
class CodeGen:
|
|
1137
|
+
def __init__(self, structs: Dict[str, StructDef],
|
|
1138
|
+
functions: Dict[str, FuncDef], filename: str = '<cin>',
|
|
1139
|
+
bounds_check: bool = False):
|
|
1140
|
+
self.structs = structs
|
|
1141
|
+
self.functions = functions
|
|
1142
|
+
self.res = CompileResult()
|
|
1143
|
+
self._filename = filename
|
|
1144
|
+
self._bounds = bounds_check
|
|
1145
|
+
|
|
1146
|
+
self.data_ptr = 0
|
|
1147
|
+
self.heap_strings: Dict[str, int] = {}
|
|
1148
|
+
|
|
1149
|
+
# 函数生成上下文
|
|
1150
|
+
self.func: Optional[FuncDef] = None
|
|
1151
|
+
self.locals: Dict[str, Tuple[Any, int, bool]] = {} # name -> (type, off, is_block)
|
|
1152
|
+
self.frame_bytes = 0
|
|
1153
|
+
self.break_labels: List[str] = []
|
|
1154
|
+
self.continue_labels: List[str] = []
|
|
1155
|
+
self.label_counter = 0
|
|
1156
|
+
|
|
1157
|
+
self.globals: Dict[str, Tuple[Any, int, bool]] = {} # name -> (type, addr, is_block)
|
|
1158
|
+
|
|
1159
|
+
# ---------------- 发射辅助 ----------------
|
|
1160
|
+
|
|
1161
|
+
def emit(self, op: str, *args: Operand) -> int:
|
|
1162
|
+
self.res.instructions.append((op, list(args)))
|
|
1163
|
+
return len(self.res.instructions) - 1
|
|
1164
|
+
|
|
1165
|
+
def label(self, name: str) -> None:
|
|
1166
|
+
self.res.labels[name] = len(self.res.instructions)
|
|
1167
|
+
|
|
1168
|
+
def new_label(self, hint: str) -> str:
|
|
1169
|
+
self.label_counter += 1
|
|
1170
|
+
return f"_{hint}_{self.label_counter}"
|
|
1171
|
+
|
|
1172
|
+
@staticmethod
|
|
1173
|
+
def reg(n: int) -> Operand:
|
|
1174
|
+
return ('reg', n)
|
|
1175
|
+
|
|
1176
|
+
@staticmethod
|
|
1177
|
+
def imm(v: int) -> Operand:
|
|
1178
|
+
return ('imm', v & 0xFFFFFFFFFFFFFFFF)
|
|
1179
|
+
|
|
1180
|
+
def lab(self, name: str) -> Operand:
|
|
1181
|
+
return ('label', name)
|
|
1182
|
+
|
|
1183
|
+
# ---------------- 数据段 ----------------
|
|
1184
|
+
|
|
1185
|
+
def _alloc_data(self, nbytes: int, align: int = 8) -> int:
|
|
1186
|
+
if align > 1:
|
|
1187
|
+
self.data_ptr = (self.data_ptr + align - 1) & ~(align - 1)
|
|
1188
|
+
addr = self.data_ptr
|
|
1189
|
+
self.data_ptr += nbytes
|
|
1190
|
+
return addr
|
|
1191
|
+
|
|
1192
|
+
def _data_string(self, text: str) -> int:
|
|
1193
|
+
if text in self.heap_strings:
|
|
1194
|
+
return self.heap_strings[text]
|
|
1195
|
+
data = text.encode('utf-8') + b'\x00'
|
|
1196
|
+
addr = self._alloc_data(len(data), align=1)
|
|
1197
|
+
self.res.data_writes.append((addr, data))
|
|
1198
|
+
self.res.data_labels[f'str_{addr:x}'] = addr
|
|
1199
|
+
self.heap_strings[text] = addr
|
|
1200
|
+
return addr
|
|
1201
|
+
|
|
1202
|
+
def _data_qword(self, value: int) -> int:
|
|
1203
|
+
addr = self._alloc_data(8)
|
|
1204
|
+
self.res.data_writes.append((addr, struct.pack('<Q', value & 0xFFFFFFFFFFFFFFFF)))
|
|
1205
|
+
return addr
|
|
1206
|
+
|
|
1207
|
+
def layout_globals(self, globals_: List[GlobalVar]) -> None:
|
|
1208
|
+
for gv in globals_:
|
|
1209
|
+
t = gv.vtype
|
|
1210
|
+
if _is_fixed_array(t):
|
|
1211
|
+
addr = self._alloc_data(_type_slots(t) * 8)
|
|
1212
|
+
self.globals[gv.name] = (t, addr, True)
|
|
1213
|
+
gv.addr = addr
|
|
1214
|
+
else:
|
|
1215
|
+
addr = self._alloc_data(8)
|
|
1216
|
+
self.globals[gv.name] = (t, addr, False)
|
|
1217
|
+
gv.addr = addr
|
|
1218
|
+
if _is_struct(t):
|
|
1219
|
+
sd = self.structs[t[1]]
|
|
1220
|
+
block = self._alloc_data(sd.size_slots * 8)
|
|
1221
|
+
self.res.data_writes.append(
|
|
1222
|
+
(addr, struct.pack('<Q', block)))
|
|
1223
|
+
|
|
1224
|
+
# ---------------- 初始化数据 ----------------
|
|
1225
|
+
|
|
1226
|
+
def _const_value(self, node) -> Tuple[Any, int]:
|
|
1227
|
+
"""编译期常量 (全局初始化用): 返回 (type, raw_bits/addr)。"""
|
|
1228
|
+
kind = node[0]
|
|
1229
|
+
if kind == 'num':
|
|
1230
|
+
if node[2]:
|
|
1231
|
+
return 'float', struct.unpack('<Q', struct.pack('<d', node[1]))[0]
|
|
1232
|
+
return 'int', node[1] & 0xFFFFFFFFFFFFFFFF
|
|
1233
|
+
if kind == 'bool':
|
|
1234
|
+
return 'bool', 1 if node[1] else 0
|
|
1235
|
+
if kind == 'str':
|
|
1236
|
+
return 'string', self._data_string(node[1])
|
|
1237
|
+
if kind == 'neg' and node[1][0] == 'num':
|
|
1238
|
+
inner = node[1]
|
|
1239
|
+
if inner[2]:
|
|
1240
|
+
return 'float', struct.unpack('<Q', struct.pack('<d', -inner[1]))[0]
|
|
1241
|
+
return 'int', (-inner[1]) & 0xFFFFFFFFFFFFFFFF
|
|
1242
|
+
if kind == 'bitnot':
|
|
1243
|
+
ctype, raw = self._const_value(node[1])
|
|
1244
|
+
if ctype not in ('int', 'bool'):
|
|
1245
|
+
raise CompilerError(f"Bitwise NOT requires integer, got: {ctype}")
|
|
1246
|
+
return 'int', (~raw) & 0xFFFFFFFFFFFFFFFF
|
|
1247
|
+
raise CompilerError(f"Non-constant global initializer: {kind}")
|
|
1248
|
+
|
|
1249
|
+
def emit_globals_init(self, globals_: List[GlobalVar]) -> None:
|
|
1250
|
+
for gv in globals_:
|
|
1251
|
+
t, addr, is_block = self.globals[gv.name]
|
|
1252
|
+
if gv.init is not None:
|
|
1253
|
+
ctype, raw = self._const_value(gv.init)
|
|
1254
|
+
self.res.data_writes.append((addr, struct.pack('<Q', raw)))
|
|
1255
|
+
elif gv.array_lit is not None:
|
|
1256
|
+
rows = gv.array_lit
|
|
1257
|
+
if rows and isinstance(rows[0], list):
|
|
1258
|
+
# 2D 字面量: 仅 ptrarray 有意义 (int[][] mat1 = ...)
|
|
1259
|
+
# 全局 2D 定长数组按行写入
|
|
1260
|
+
for i, row in enumerate(rows):
|
|
1261
|
+
for j, elem in enumerate(row):
|
|
1262
|
+
_, raw = self._const_value(elem)
|
|
1263
|
+
self.res.data_writes.append(
|
|
1264
|
+
(addr + (i * len(row) + j) * 8, struct.pack('<Q', raw)))
|
|
1265
|
+
else:
|
|
1266
|
+
for i, elem in enumerate(rows):
|
|
1267
|
+
_, raw = self._const_value(elem)
|
|
1268
|
+
self.res.data_writes.append((addr + i * 8, struct.pack('<Q', raw)))
|
|
1269
|
+
|
|
1270
|
+
# ---------------- 主生成 ----------------
|
|
1271
|
+
|
|
1272
|
+
def generate(self, globals_: List[GlobalVar],
|
|
1273
|
+
functions: Dict[str, FuncDef]) -> CompileResult:
|
|
1274
|
+
self.emit_globals_init(globals_)
|
|
1275
|
+
|
|
1276
|
+
# 入口: CALL main; HALT
|
|
1277
|
+
self.emit('CALL', self.lab('main'))
|
|
1278
|
+
self.emit('HALT')
|
|
1279
|
+
|
|
1280
|
+
for _fname, fdef in functions.items():
|
|
1281
|
+
self.gen_function(fdef)
|
|
1282
|
+
|
|
1283
|
+
return self.res
|
|
1284
|
+
|
|
1285
|
+
# ---------------- 栈帧 ----------------
|
|
1286
|
+
|
|
1287
|
+
def _prescan_locals(self, body: list) -> List[Tuple[str, Any, int]]:
|
|
1288
|
+
"""收集函数内所有局部声明 (含 for 初始化), 返回 (name,type,slots)。"""
|
|
1289
|
+
found: List[Tuple[str, Any, int]] = []
|
|
1290
|
+
seen = set()
|
|
1291
|
+
|
|
1292
|
+
def walk(stmts):
|
|
1293
|
+
for s in stmts:
|
|
1294
|
+
kind = s[0]
|
|
1295
|
+
if kind == 'decl':
|
|
1296
|
+
for name, t, _init, _al in s[1]:
|
|
1297
|
+
if name in seen:
|
|
1298
|
+
continue
|
|
1299
|
+
seen.add(name)
|
|
1300
|
+
found.append((name, t, _type_slots(t)))
|
|
1301
|
+
elif kind == 'block':
|
|
1302
|
+
walk(s[1])
|
|
1303
|
+
elif kind == 'if':
|
|
1304
|
+
walk([s[2]])
|
|
1305
|
+
if s[3]:
|
|
1306
|
+
walk([s[3]])
|
|
1307
|
+
elif kind == 'while':
|
|
1308
|
+
walk([s[2]])
|
|
1309
|
+
elif kind == 'dowhile':
|
|
1310
|
+
walk([s[1]])
|
|
1311
|
+
elif kind == 'switch':
|
|
1312
|
+
for _bk, _const, stmts in s[2]:
|
|
1313
|
+
walk(stmts)
|
|
1314
|
+
elif kind == 'for':
|
|
1315
|
+
if s[1] is not None and s[1][0] == 'decl':
|
|
1316
|
+
for name, t, _i, _a in s[1][1]:
|
|
1317
|
+
if name not in seen:
|
|
1318
|
+
seen.add(name)
|
|
1319
|
+
found.append((name, t, _type_slots(t)))
|
|
1320
|
+
walk([s[4]])
|
|
1321
|
+
walk(body)
|
|
1322
|
+
return found
|
|
1323
|
+
|
|
1324
|
+
def gen_function(self, f: FuncDef) -> None:
|
|
1325
|
+
self.func = f
|
|
1326
|
+
self.locals = {}
|
|
1327
|
+
self.break_labels = []
|
|
1328
|
+
self.continue_labels = []
|
|
1329
|
+
|
|
1330
|
+
# 局部变量布局 (自 FP 向下分配):
|
|
1331
|
+
# 标量槽地址 = fp-(8+off); 数组块基址 = fp-(off+slots*8)
|
|
1332
|
+
# (元素从基址向高地址生长, 不与后续变量冲突)
|
|
1333
|
+
locals_info = self._prescan_locals(f.body)
|
|
1334
|
+
off = 0
|
|
1335
|
+
for name, t, slots in locals_info:
|
|
1336
|
+
self.locals[name] = (t, -(off + slots * 8), _is_fixed_array(t))
|
|
1337
|
+
off += slots * 8
|
|
1338
|
+
self.frame_bytes = off
|
|
1339
|
+
|
|
1340
|
+
# 参数位置 (相对 FP): fp+16 为第一个压栈参数 (最左)
|
|
1341
|
+
# 帧布局: [参数...][返回地址(fp+8)][保存的FP(fp)][局部...]
|
|
1342
|
+
nargs = len(f.params)
|
|
1343
|
+
for k, (pname, ptype) in enumerate(f.params):
|
|
1344
|
+
poff = 16 + (nargs - 1 - k) * 8
|
|
1345
|
+
self.locals[pname] = (ptype, poff, False)
|
|
1346
|
+
|
|
1347
|
+
self.label(f.name)
|
|
1348
|
+
# prologue: 保存调用方 FP, 建立帧指针, 分配局部空间
|
|
1349
|
+
self.emit('PUSH', self.reg(29))
|
|
1350
|
+
self.emit('MOV', self.reg(29), self.reg(32)) # FP = SP
|
|
1351
|
+
if self.frame_bytes:
|
|
1352
|
+
self.emit('ADDI', self.reg(0), self.reg(32), self.imm(-self.frame_bytes))
|
|
1353
|
+
self.emit('MOV', self.reg(32), self.reg(0))
|
|
1354
|
+
|
|
1355
|
+
# struct 局部变量: 堆分配对象
|
|
1356
|
+
for _name, (t, loff, _is_block) in list(self.locals.items()):
|
|
1357
|
+
if _is_struct(t) and loff < 0:
|
|
1358
|
+
sd = self.structs[t[1]]
|
|
1359
|
+
self.emit('MOV', self.reg(0), self.imm(sd.size_slots * 8))
|
|
1360
|
+
self.emit('SYS', self.imm(Syscall.MALLOC))
|
|
1361
|
+
self.emit('MOV', self.reg(2), self.reg(0)) # 对象指针
|
|
1362
|
+
self._addr_local(loff) # x0 = &slot
|
|
1363
|
+
self.emit('SD', self.reg(2), ('mem', 0, 0))
|
|
1364
|
+
|
|
1365
|
+
self.gen_stmts(f.body)
|
|
1366
|
+
|
|
1367
|
+
# epilogue
|
|
1368
|
+
self._epilogue()
|
|
1369
|
+
|
|
1370
|
+
def _epilogue(self) -> None:
|
|
1371
|
+
# 不得破坏 x0 (返回值)
|
|
1372
|
+
self.emit('MOV', self.reg(6), self.reg(29)) # SP = FP
|
|
1373
|
+
self.emit('MOV', self.reg(32), self.reg(6))
|
|
1374
|
+
self.emit('POP', self.reg(29)) # 恢复调用方 FP
|
|
1375
|
+
self.emit('RET')
|
|
1376
|
+
|
|
1377
|
+
def _addr_local(self, off: int) -> None:
|
|
1378
|
+
"""x0 = FP + off (局部 off 为负, 参数 off 为正)。"""
|
|
1379
|
+
if off == 0:
|
|
1380
|
+
self.emit('MOV', self.reg(0), self.reg(29))
|
|
1381
|
+
else:
|
|
1382
|
+
self.emit('ADDI', self.reg(0), self.reg(29), self.imm(off))
|
|
1383
|
+
|
|
1384
|
+
def _addr_var(self, name: str) -> None:
|
|
1385
|
+
"""x0 = 变量槽地址。"""
|
|
1386
|
+
if name in self.locals:
|
|
1387
|
+
_t, off, _is_block = self.locals[name]
|
|
1388
|
+
self._addr_local(off)
|
|
1389
|
+
elif name in self.globals:
|
|
1390
|
+
_t, addr, _is_block = self.globals[name]
|
|
1391
|
+
self.emit('MOV', self.reg(0), self.imm(addr))
|
|
1392
|
+
else:
|
|
1393
|
+
raise CompilerError(f"Undefined variable: {name}")
|
|
1394
|
+
|
|
1395
|
+
def _var_type(self, name: str):
|
|
1396
|
+
if name in self.locals:
|
|
1397
|
+
return self.locals[name][0]
|
|
1398
|
+
if name in self.globals:
|
|
1399
|
+
return self.globals[name][0]
|
|
1400
|
+
return None
|
|
1401
|
+
|
|
1402
|
+
# ---------------- 语句 ----------------
|
|
1403
|
+
|
|
1404
|
+
def gen_stmts(self, stmts: list) -> None:
|
|
1405
|
+
for s in stmts:
|
|
1406
|
+
self.gen_stmt(s)
|
|
1407
|
+
|
|
1408
|
+
def gen_stmt(self, s) -> None:
|
|
1409
|
+
kind = s[0]
|
|
1410
|
+
if kind == 'block':
|
|
1411
|
+
self.gen_stmts(s[1])
|
|
1412
|
+
elif kind == 'return':
|
|
1413
|
+
if s[1] is not None:
|
|
1414
|
+
t = self.gen_value(s[1])
|
|
1415
|
+
self._convert(t, self.func.ret_type)
|
|
1416
|
+
self._epilogue()
|
|
1417
|
+
elif kind == 'if':
|
|
1418
|
+
self.gen_if(s[1], s[2], s[3])
|
|
1419
|
+
elif kind == 'while':
|
|
1420
|
+
self.gen_while(s[1], s[2])
|
|
1421
|
+
elif kind == 'for':
|
|
1422
|
+
self.gen_for(s[1], s[2], s[3], s[4])
|
|
1423
|
+
elif kind == 'dowhile':
|
|
1424
|
+
self.gen_dowhile(s[1], s[2])
|
|
1425
|
+
elif kind == 'switch':
|
|
1426
|
+
self.gen_switch(s[1], s[2])
|
|
1427
|
+
elif kind == 'break':
|
|
1428
|
+
if not self.break_labels:
|
|
1429
|
+
raise CompilerError("break outside loop")
|
|
1430
|
+
self.emit('JMP', self.lab(self.break_labels[-1]))
|
|
1431
|
+
elif kind == 'continue':
|
|
1432
|
+
if not self.continue_labels:
|
|
1433
|
+
raise CompilerError("continue outside loop")
|
|
1434
|
+
self.emit('JMP', self.lab(self.continue_labels[-1]))
|
|
1435
|
+
elif kind == 'decl':
|
|
1436
|
+
self.gen_decl(s[1])
|
|
1437
|
+
elif kind == 'cpu':
|
|
1438
|
+
self.gen_cpu_stmt(s[1], s[2])
|
|
1439
|
+
elif kind == 'assert':
|
|
1440
|
+
self.gen_assert(s[1], s[2], s[3],
|
|
1441
|
+
s[4] if len(s) > 4 else self._filename)
|
|
1442
|
+
elif kind == 'expr':
|
|
1443
|
+
self.gen_expr_stmt(s[1])
|
|
1444
|
+
|
|
1445
|
+
def gen_if(self, cond, then_body, else_body) -> None:
|
|
1446
|
+
l_else = self.new_label('else')
|
|
1447
|
+
l_end = self.new_label('endif')
|
|
1448
|
+
target = l_else if else_body is not None else l_end
|
|
1449
|
+
self.gen_cond_jump_false(cond, target)
|
|
1450
|
+
self.gen_stmt(then_body)
|
|
1451
|
+
if else_body is not None:
|
|
1452
|
+
self.emit('JMP', self.lab(l_end))
|
|
1453
|
+
self.label(l_else)
|
|
1454
|
+
self.gen_stmt(else_body)
|
|
1455
|
+
self.label(l_end)
|
|
1456
|
+
|
|
1457
|
+
def gen_while(self, cond, body) -> None:
|
|
1458
|
+
l_start = self.new_label('while')
|
|
1459
|
+
l_end = self.new_label('wend')
|
|
1460
|
+
self.label(l_start)
|
|
1461
|
+
self.gen_cond_jump_false(cond, l_end)
|
|
1462
|
+
self.break_labels.append(l_end)
|
|
1463
|
+
self.continue_labels.append(l_start)
|
|
1464
|
+
self.gen_stmt(body)
|
|
1465
|
+
self.emit('JMP', self.lab(l_start))
|
|
1466
|
+
self.break_labels.pop()
|
|
1467
|
+
self.continue_labels.pop()
|
|
1468
|
+
self.label(l_end)
|
|
1469
|
+
|
|
1470
|
+
def gen_for(self, init, cond, update, body) -> None:
|
|
1471
|
+
if init is not None:
|
|
1472
|
+
self.gen_stmt(init)
|
|
1473
|
+
l_cond = self.new_label('forc')
|
|
1474
|
+
l_update = self.new_label('foru')
|
|
1475
|
+
l_end = self.new_label('fore')
|
|
1476
|
+
self.label(l_cond)
|
|
1477
|
+
if cond is not None:
|
|
1478
|
+
self.gen_cond_jump_false(cond, l_end)
|
|
1479
|
+
self.break_labels.append(l_end)
|
|
1480
|
+
self.continue_labels.append(l_update)
|
|
1481
|
+
self.gen_stmt(body)
|
|
1482
|
+
self.label(l_update)
|
|
1483
|
+
if update is not None:
|
|
1484
|
+
self.gen_stmt(update)
|
|
1485
|
+
self.emit('JMP', self.lab(l_cond))
|
|
1486
|
+
self.break_labels.pop()
|
|
1487
|
+
self.continue_labels.pop()
|
|
1488
|
+
self.label(l_end)
|
|
1489
|
+
|
|
1490
|
+
def gen_dowhile(self, body, cond) -> None:
|
|
1491
|
+
l_body = self.new_label('dbody')
|
|
1492
|
+
l_cond = self.new_label('dcond')
|
|
1493
|
+
l_end = self.new_label('dend')
|
|
1494
|
+
self.label(l_body)
|
|
1495
|
+
self.break_labels.append(l_end)
|
|
1496
|
+
self.continue_labels.append(l_cond)
|
|
1497
|
+
self.gen_stmt(body)
|
|
1498
|
+
self.label(l_cond)
|
|
1499
|
+
self.gen_cond_jump_false(cond, l_end)
|
|
1500
|
+
self.emit('JMP', self.lab(l_body))
|
|
1501
|
+
self.break_labels.pop()
|
|
1502
|
+
self.continue_labels.pop()
|
|
1503
|
+
self.label(l_end)
|
|
1504
|
+
|
|
1505
|
+
def gen_switch(self, cond, branches) -> None:
|
|
1506
|
+
"""switch: 选择器压栈, CMP 链分派, case 体按文字顺序内联 (C 贯穿语义)。"""
|
|
1507
|
+
sel_t = self._expr_type(cond)
|
|
1508
|
+
if sel_t not in ('int', 'bool'):
|
|
1509
|
+
raise CompilerError(
|
|
1510
|
+
f"Switch expression must be integer, got: {sel_t}")
|
|
1511
|
+
l_end = self.new_label('swend')
|
|
1512
|
+
self.break_labels.append(l_end)
|
|
1513
|
+
# continue 必须先把选择器弹出再跳, 否则每轮迭代泄漏 8 字节栈直至撞堆。
|
|
1514
|
+
# 只有在循环内 (存在外层 continue 目标) 才接管 continue, 否则保持
|
|
1515
|
+
# "continue outside loop" 报错语义。
|
|
1516
|
+
outer_cont = self.continue_labels[-1] if self.continue_labels else None
|
|
1517
|
+
l_cont = None
|
|
1518
|
+
if outer_cont is not None:
|
|
1519
|
+
l_cont = self.new_label('swcont')
|
|
1520
|
+
self.continue_labels.append(l_cont)
|
|
1521
|
+
self.gen_value(cond)
|
|
1522
|
+
self.emit('PUSH', self.reg(0)) # [SP] = selector
|
|
1523
|
+
|
|
1524
|
+
labels: List[Tuple[Optional[int], str]] = []
|
|
1525
|
+
default_lbl: Optional[str] = None
|
|
1526
|
+
for _kind, const, _stmts in branches:
|
|
1527
|
+
if const is None:
|
|
1528
|
+
lbl = self.new_label('swdef')
|
|
1529
|
+
default_lbl = lbl
|
|
1530
|
+
labels.append((None, lbl))
|
|
1531
|
+
continue
|
|
1532
|
+
try:
|
|
1533
|
+
ctype, raw = self._const_value(const)
|
|
1534
|
+
except CompilerError:
|
|
1535
|
+
raise CompilerError(
|
|
1536
|
+
"case value must be an integer constant") from None
|
|
1537
|
+
if ctype not in ('int', 'bool'):
|
|
1538
|
+
raise CompilerError(
|
|
1539
|
+
f"case value must be an integer constant, got: {ctype}")
|
|
1540
|
+
labels.append((raw & 0xFFFFFFFFFFFFFFFF, self.new_label('swcase')))
|
|
1541
|
+
|
|
1542
|
+
# 分派比较链
|
|
1543
|
+
for raw, lbl in labels:
|
|
1544
|
+
if raw is None:
|
|
1545
|
+
continue
|
|
1546
|
+
self.emit('LD', self.reg(0), ('mem', 32, 0))
|
|
1547
|
+
self.emit('MOV', self.reg(1), self.imm(raw))
|
|
1548
|
+
self.emit('CMP', self.reg(0), self.reg(1))
|
|
1549
|
+
self.emit('B', self.lab(lbl), ('cond', 'EQ'))
|
|
1550
|
+
self.emit('JMP', self.lab(default_lbl if default_lbl is not None
|
|
1551
|
+
else l_end))
|
|
1552
|
+
|
|
1553
|
+
# case/default 体 (inline, 贯穿)
|
|
1554
|
+
for idx, (_kind, _const, stmts) in enumerate(branches):
|
|
1555
|
+
self.label(labels[idx][1])
|
|
1556
|
+
self.gen_stmts(stmts)
|
|
1557
|
+
|
|
1558
|
+
# 贯穿到末尾与 break 都必须走弹出选择器的路径
|
|
1559
|
+
self.emit('JMP', self.lab(l_end))
|
|
1560
|
+
if l_cont is not None:
|
|
1561
|
+
self.label(l_cont)
|
|
1562
|
+
self.emit('ADDI', self.reg(32), self.reg(32), self.imm(8))
|
|
1563
|
+
self.emit('JMP', self.lab(outer_cont))
|
|
1564
|
+
self.continue_labels.pop()
|
|
1565
|
+
self.label(l_end)
|
|
1566
|
+
self.break_labels.pop()
|
|
1567
|
+
self.emit('ADDI', self.reg(32), self.reg(32), self.imm(8)) # 丢 selector
|
|
1568
|
+
|
|
1569
|
+
def gen_decl(self, decls) -> None:
|
|
1570
|
+
for name, t, init, array_lit in decls:
|
|
1571
|
+
if array_lit is not None:
|
|
1572
|
+
if array_lit and isinstance(array_lit[0], list):
|
|
1573
|
+
self.gen_init_2d_literal(name, t, array_lit)
|
|
1574
|
+
else:
|
|
1575
|
+
self.gen_init_1d_literal(name, t, array_lit)
|
|
1576
|
+
continue
|
|
1577
|
+
if init is not None:
|
|
1578
|
+
vt = self.gen_value(init)
|
|
1579
|
+
self._convert(vt, t)
|
|
1580
|
+
# x0 = value; 存到变量槽
|
|
1581
|
+
self.emit('MOV', self.reg(2), self.reg(0))
|
|
1582
|
+
self._addr_var(name)
|
|
1583
|
+
self.emit('SD', self.reg(2), ('mem', 0, 0))
|
|
1584
|
+
elif _is_ptr_array(t) and _is_ptr_array(_array_elem(t)):
|
|
1585
|
+
# int[][] result (无尺寸): 预分配 64 个行指针
|
|
1586
|
+
self.emit('MOV', self.reg(0), self.imm(64 * 8))
|
|
1587
|
+
self.emit('SYS', self.imm(Syscall.MALLOC))
|
|
1588
|
+
self.emit('MOV', self.reg(2), self.reg(0))
|
|
1589
|
+
self._addr_var(name)
|
|
1590
|
+
self.emit('SD', self.reg(2), ('mem', 0, 0))
|
|
1591
|
+
|
|
1592
|
+
def gen_init_1d_literal(self, name: str, t, elems: list) -> None:
|
|
1593
|
+
# 定长 1D 数组: 就地写入 (每轮重新取基址, 避免地址累加)
|
|
1594
|
+
elem_t = _array_elem(t) if _is_fixed_array(t) else 'int'
|
|
1595
|
+
for i, elem in enumerate(elems):
|
|
1596
|
+
vt = self.gen_value(elem)
|
|
1597
|
+
self._convert(vt, elem_t)
|
|
1598
|
+
self.emit('MOV', self.reg(2), self.reg(0)) # value
|
|
1599
|
+
self._addr_var(name) # x0 = base
|
|
1600
|
+
if i:
|
|
1601
|
+
self.emit('ADDI', self.reg(0), self.reg(0), self.imm(i * 8))
|
|
1602
|
+
self.emit('SD', self.reg(2), ('mem', 0, 0))
|
|
1603
|
+
|
|
1604
|
+
def gen_init_2d_literal(self, name: str, t, rows: list) -> None:
|
|
1605
|
+
# int[][] mat1 = {{...},{...}}: 堆分配行指针数组 + 每行
|
|
1606
|
+
nrows = len(rows)
|
|
1607
|
+
ncols = max(len(r) for r in rows)
|
|
1608
|
+
# 外层: nrows 个指针
|
|
1609
|
+
self.emit('MOV', self.reg(0), self.imm(nrows * 8))
|
|
1610
|
+
self.emit('SYS', self.imm(Syscall.MALLOC))
|
|
1611
|
+
self.emit('MOV', self.reg(4), self.reg(0)) # outer
|
|
1612
|
+
for i, row in enumerate(rows):
|
|
1613
|
+
self.emit('MOV', self.reg(0), self.imm(max(ncols, 1) * 8))
|
|
1614
|
+
self.emit('SYS', self.imm(Syscall.MALLOC))
|
|
1615
|
+
self.emit('MOV', self.reg(5), self.reg(0)) # row ptr
|
|
1616
|
+
# outer[i] = row ptr
|
|
1617
|
+
self.emit('MOV', self.reg(0), self.reg(4))
|
|
1618
|
+
self.emit('ADDI', self.reg(0), self.reg(0), self.imm(i * 8))
|
|
1619
|
+
self.emit('SD', self.reg(5), ('mem', 0, 0))
|
|
1620
|
+
for j, elem in enumerate(row):
|
|
1621
|
+
vt = self.gen_value(elem)
|
|
1622
|
+
self._convert(vt, 'int')
|
|
1623
|
+
self.emit('MOV', self.reg(2), self.reg(0))
|
|
1624
|
+
self.emit('MOV', self.reg(0), self.reg(5))
|
|
1625
|
+
if j:
|
|
1626
|
+
self.emit('ADDI', self.reg(0), self.reg(0), self.imm(j * 8))
|
|
1627
|
+
self.emit('SD', self.reg(2), ('mem', 0, 0))
|
|
1628
|
+
# 保存 outer 到变量槽
|
|
1629
|
+
self.emit('MOV', self.reg(2), self.reg(4))
|
|
1630
|
+
self._addr_var(name)
|
|
1631
|
+
self.emit('SD', self.reg(2), ('mem', 0, 0))
|
|
1632
|
+
|
|
1633
|
+
def gen_cpu_stmt(self, op: str, operands: list) -> None:
|
|
1634
|
+
def operand_value(operand):
|
|
1635
|
+
kind, val = operand
|
|
1636
|
+
if kind == 'NUMBER':
|
|
1637
|
+
return val
|
|
1638
|
+
if kind == 'IDENT':
|
|
1639
|
+
return ('var', val)
|
|
1640
|
+
raise CompilerError(f"Bad CPU-style operand: {operand}")
|
|
1641
|
+
|
|
1642
|
+
if op in ('increment', 'decrement'):
|
|
1643
|
+
varname = operands[0][1]
|
|
1644
|
+
self._addr_var(varname)
|
|
1645
|
+
self.emit('LD', self.reg(0), ('mem', 0, 0))
|
|
1646
|
+
self.emit('INC' if op == 'increment' else 'DEC', self.reg(0))
|
|
1647
|
+
self.emit('MOV', self.reg(2), self.reg(0))
|
|
1648
|
+
self._addr_var(varname)
|
|
1649
|
+
self.emit('SD', self.reg(2), ('mem', 0, 0))
|
|
1650
|
+
return
|
|
1651
|
+
|
|
1652
|
+
varname = operands[0][1]
|
|
1653
|
+
rhs = operand_value(operands[1]) if len(operands) > 1 else None
|
|
1654
|
+
|
|
1655
|
+
if op == 'set':
|
|
1656
|
+
if isinstance(rhs, tuple):
|
|
1657
|
+
self.gen_value(rhs)
|
|
1658
|
+
else:
|
|
1659
|
+
self.emit('MOV', self.reg(0), self.imm(int(rhs)))
|
|
1660
|
+
else:
|
|
1661
|
+
# add/subtract/multiply/divide: var = var op rhs (整数)
|
|
1662
|
+
self._addr_var(varname)
|
|
1663
|
+
self.emit('LD', self.reg(0), ('mem', 0, 0))
|
|
1664
|
+
if isinstance(rhs, tuple):
|
|
1665
|
+
self.emit('MOV', self.reg(2), self.reg(0))
|
|
1666
|
+
self.gen_value(rhs)
|
|
1667
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
1668
|
+
self.emit('MOV', self.reg(0), self.reg(2))
|
|
1669
|
+
else:
|
|
1670
|
+
self.emit('MOV', self.reg(1), self.imm(int(rhs)))
|
|
1671
|
+
op_map = {'add': 'ADD', 'subtract': 'SUB',
|
|
1672
|
+
'multiply': 'MUL', 'divide': 'DIV'}
|
|
1673
|
+
self.emit(op_map[op], self.reg(0), self.reg(1))
|
|
1674
|
+
self.emit('MOV', self.reg(2), self.reg(0))
|
|
1675
|
+
self._addr_var(varname)
|
|
1676
|
+
self.emit('SD', self.reg(2), ('mem', 0, 0))
|
|
1677
|
+
|
|
1678
|
+
def gen_expr_stmt(self, node) -> None:
|
|
1679
|
+
# 赋值
|
|
1680
|
+
if node[0] == 'binop' and node[1] == '=':
|
|
1681
|
+
pass
|
|
1682
|
+
# parse 不产生 '=' binop; 赋值在 parse 层未处理, 这里检测 call/var 链
|
|
1683
|
+
self.gen_value(node)
|
|
1684
|
+
|
|
1685
|
+
# ---------------- 运行时断言 / 中止 (A1) ----------------
|
|
1686
|
+
|
|
1687
|
+
def _runtime_abort(self, text: str) -> None:
|
|
1688
|
+
"""SYS ABORT: 加载静态消息指针并抛出运行时错误。"""
|
|
1689
|
+
addr = self._data_string(text)
|
|
1690
|
+
self.emit('MOV', self.reg(0), self.imm(addr))
|
|
1691
|
+
self.emit('SYS', self.imm(Syscall.ABORT))
|
|
1692
|
+
|
|
1693
|
+
def gen_assert(self, cond, msg, line: int,
|
|
1694
|
+
filename: Optional[str] = None) -> None:
|
|
1695
|
+
"""assert(cond [, msg]) → 条件不成立时运行时中止 (定位: filename:line)。"""
|
|
1696
|
+
l_ok = self.new_label('assertok')
|
|
1697
|
+
self.gen_cond_jump_true(cond, l_ok)
|
|
1698
|
+
if msg is None:
|
|
1699
|
+
self._runtime_abort(
|
|
1700
|
+
f"{(filename or self._filename)}:{line}: assertion failed")
|
|
1701
|
+
else:
|
|
1702
|
+
# [prefix] + 消息 (消息支持任意表达式, 自动字符串化)
|
|
1703
|
+
prefix = self._data_string(
|
|
1704
|
+
f"[assert {(filename or self._filename)}:{line}] ")
|
|
1705
|
+
self.emit('MOV', self.reg(0), self.imm(prefix))
|
|
1706
|
+
self.emit('PUSH', self.reg(0))
|
|
1707
|
+
self._gen_string_value(msg)
|
|
1708
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
1709
|
+
self.emit('POP', self.reg(0))
|
|
1710
|
+
self.emit('SYS', self.imm(Syscall.STR_CONCAT))
|
|
1711
|
+
self.emit('SYS', self.imm(Syscall.ABORT))
|
|
1712
|
+
self.label(l_ok)
|
|
1713
|
+
|
|
1714
|
+
# ---------------- 类型转换 ----------------
|
|
1715
|
+
|
|
1716
|
+
def _convert(self, from_type, to_type) -> None:
|
|
1717
|
+
"""将 x0 从 from_type 转换为 to_type (原地)。"""
|
|
1718
|
+
if to_type is None or from_type is None:
|
|
1719
|
+
return
|
|
1720
|
+
if from_type == to_type:
|
|
1721
|
+
return
|
|
1722
|
+
if from_type == 'int' and to_type == 'float':
|
|
1723
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
1724
|
+
elif from_type == 'float' and to_type == 'int':
|
|
1725
|
+
self.emit('SYS', self.imm(Syscall.FTOI))
|
|
1726
|
+
elif from_type == 'bool' and to_type in ('int', 'float'):
|
|
1727
|
+
if to_type == 'float':
|
|
1728
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
1729
|
+
elif from_type == 'int' and to_type == 'bool':
|
|
1730
|
+
pass
|
|
1731
|
+
# string/struct/array 指针无需转换
|
|
1732
|
+
|
|
1733
|
+
# ---------------- 表达式 ----------------
|
|
1734
|
+
|
|
1735
|
+
def gen_value(self, node) -> Any:
|
|
1736
|
+
"""求值表达式到 x0, 返回 CIN 类型。"""
|
|
1737
|
+
kind = node[0]
|
|
1738
|
+
if kind == 'num':
|
|
1739
|
+
if node[2]:
|
|
1740
|
+
bits = struct.unpack('<Q', struct.pack('<d', float(node[1])))[0]
|
|
1741
|
+
self.emit('MOV', self.reg(0), self.imm(bits))
|
|
1742
|
+
return 'float'
|
|
1743
|
+
self.emit('MOV', self.reg(0), self.imm(int(node[1])))
|
|
1744
|
+
return 'int'
|
|
1745
|
+
if kind == 'bool':
|
|
1746
|
+
self.emit('MOV', self.reg(0), self.imm(1 if node[1] else 0))
|
|
1747
|
+
return 'bool'
|
|
1748
|
+
if kind == 'str':
|
|
1749
|
+
self.emit('MOV', self.reg(0), self.imm(self._data_string(node[1])))
|
|
1750
|
+
return 'string'
|
|
1751
|
+
if kind == 'var':
|
|
1752
|
+
return self._gen_var_value(node[1])
|
|
1753
|
+
if kind == 'member':
|
|
1754
|
+
return self._gen_member(node[1], node[2], lvalue=False)
|
|
1755
|
+
if kind == 'index':
|
|
1756
|
+
return self._gen_index(node[1], node[2], lvalue=False)
|
|
1757
|
+
if kind == 'call':
|
|
1758
|
+
return self._gen_call(node[1], node[2])
|
|
1759
|
+
if kind == 'neg':
|
|
1760
|
+
t = self.gen_value(node[1])
|
|
1761
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
1762
|
+
if t == 'float':
|
|
1763
|
+
# 浮点: 0.0 - x (x1 为 float64 位模式)
|
|
1764
|
+
self.emit('MOV', self.reg(0), self.imm(0))
|
|
1765
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
1766
|
+
self.emit('SYS', self.imm(Syscall.FSUB))
|
|
1767
|
+
else:
|
|
1768
|
+
self.emit('MOV', self.reg(0), self.imm(0))
|
|
1769
|
+
self.emit('SUB', self.reg(0), self.reg(1))
|
|
1770
|
+
return t
|
|
1771
|
+
if kind == 'not':
|
|
1772
|
+
t = self.gen_value(node[1])
|
|
1773
|
+
self.emit('XORI', self.reg(0), self.reg(0), self.imm(1))
|
|
1774
|
+
return 'bool'
|
|
1775
|
+
if kind == 'bitnot':
|
|
1776
|
+
t = self.gen_value(node[1])
|
|
1777
|
+
if t in ('float', 'string'):
|
|
1778
|
+
raise CompilerError("Bitwise NOT '~' requires an integer operand")
|
|
1779
|
+
self.emit('MVN', self.reg(0), self.reg(0))
|
|
1780
|
+
return 'int'
|
|
1781
|
+
if kind in ('preinc', 'predec', 'postinc', 'postdec'):
|
|
1782
|
+
return self._gen_incdec(kind, node[1])
|
|
1783
|
+
if kind == 'cond':
|
|
1784
|
+
return self._gen_ternary(node[1], node[2], node[3])
|
|
1785
|
+
if kind == 'binop':
|
|
1786
|
+
return self._gen_binop(node[1], node[2], node[3])
|
|
1787
|
+
raise CompilerError(f"Cannot generate code for expression: {kind}")
|
|
1788
|
+
|
|
1789
|
+
def _gen_var_value(self, name: str) -> Any:
|
|
1790
|
+
t = self._var_type(name)
|
|
1791
|
+
if t is None:
|
|
1792
|
+
raise CompilerError(f"Undefined variable: {name}")
|
|
1793
|
+
is_block = False
|
|
1794
|
+
if name in self.locals:
|
|
1795
|
+
is_block = self.locals[name][2]
|
|
1796
|
+
elif name in self.globals:
|
|
1797
|
+
is_block = self.globals[name][2]
|
|
1798
|
+
if is_block:
|
|
1799
|
+
# 定长数组: 值 = 块地址
|
|
1800
|
+
self._addr_var(name)
|
|
1801
|
+
return t
|
|
1802
|
+
self._addr_var(name)
|
|
1803
|
+
self.emit('LD', self.reg(0), ('mem', 0, 0))
|
|
1804
|
+
return t
|
|
1805
|
+
|
|
1806
|
+
def _gen_lvalue_addr(self, node) -> None:
|
|
1807
|
+
"""求值左值地址到 x0。"""
|
|
1808
|
+
kind = node[0]
|
|
1809
|
+
if kind == 'var':
|
|
1810
|
+
self._addr_var(node[1])
|
|
1811
|
+
return
|
|
1812
|
+
if kind == 'member':
|
|
1813
|
+
self._gen_member(node[1], node[2], lvalue=True)
|
|
1814
|
+
return
|
|
1815
|
+
if kind == 'index':
|
|
1816
|
+
self._gen_index(node[1], node[2], lvalue=True)
|
|
1817
|
+
return
|
|
1818
|
+
raise CompilerError(f"Invalid assignment target: {kind}")
|
|
1819
|
+
|
|
1820
|
+
def _struct_field(self, struct_type, fname: str) -> Tuple[Any, int]:
|
|
1821
|
+
sd = self.structs[struct_type[1]]
|
|
1822
|
+
if fname not in sd.offsets:
|
|
1823
|
+
raise CompilerError(f"Struct {struct_type[1]} has no field {fname}")
|
|
1824
|
+
ftype = dict(sd.fields)[fname]
|
|
1825
|
+
return ftype, sd.offsets[fname]
|
|
1826
|
+
|
|
1827
|
+
def _gen_member(self, obj_node, fname: str, lvalue: bool):
|
|
1828
|
+
obj_t = self.gen_value(obj_node) # x0 = struct 指针
|
|
1829
|
+
if not _is_struct(obj_t):
|
|
1830
|
+
raise CompilerError(f"Member access on non-struct type: {obj_t}")
|
|
1831
|
+
ftype, foff = self._struct_field(obj_t, fname)
|
|
1832
|
+
if lvalue:
|
|
1833
|
+
if foff:
|
|
1834
|
+
self.emit('ADDI', self.reg(0), self.reg(0), self.imm(foff * 8))
|
|
1835
|
+
return None
|
|
1836
|
+
# 值
|
|
1837
|
+
if _is_fixed_array(ftype):
|
|
1838
|
+
# 内联数组: 值 = 字段地址, 类型退化为指针视图
|
|
1839
|
+
if foff:
|
|
1840
|
+
self.emit('ADDI', self.reg(0), self.reg(0), self.imm(foff * 8))
|
|
1841
|
+
return self._decay(ftype)
|
|
1842
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
1843
|
+
if foff:
|
|
1844
|
+
self.emit('ADDI', self.reg(1), self.reg(1), self.imm(foff * 8))
|
|
1845
|
+
self.emit('LD', self.reg(0), ('mem', 1, 0))
|
|
1846
|
+
return ftype
|
|
1847
|
+
|
|
1848
|
+
@staticmethod
|
|
1849
|
+
def _decay(t):
|
|
1850
|
+
"""定长数组作为指针值时的类型视图。"""
|
|
1851
|
+
if _is_fixed_array(t):
|
|
1852
|
+
elem = t[1]
|
|
1853
|
+
if _is_fixed_array(elem):
|
|
1854
|
+
return ('array', elem, t[2]) # 多维: 子数组仍定长
|
|
1855
|
+
return ('ptrarray', elem)
|
|
1856
|
+
return t
|
|
1857
|
+
|
|
1858
|
+
def _gen_index(self, base_node, idx_node, lvalue: bool):
|
|
1859
|
+
base_t = self.gen_value(base_node) # 定长数组=块地址; ptrarray=指针; string=ptr
|
|
1860
|
+
if base_t == 'string':
|
|
1861
|
+
if lvalue:
|
|
1862
|
+
raise CompilerError(
|
|
1863
|
+
"Cannot assign to string element (strings are immutable)")
|
|
1864
|
+
self.emit('MOV', self.reg(3), self.reg(0)) # x3 = 字符串基址
|
|
1865
|
+
self.gen_value(idx_node) # x0 = index
|
|
1866
|
+
self.emit('ADD', self.reg(0), self.reg(3)) # x0 = base + i (字节偏移)
|
|
1867
|
+
self.emit('LB', self.reg(0), ('mem', 0, 0)) # 读 1 字节 (符号扩展)
|
|
1868
|
+
self.emit('ANDI', self.reg(0), self.reg(0), self.imm(0xFF)) # 0..255
|
|
1869
|
+
return 'int'
|
|
1870
|
+
if _is_fixed_array(base_t) or _is_ptr_array(base_t):
|
|
1871
|
+
elem_t = _array_elem(base_t)
|
|
1872
|
+
else:
|
|
1873
|
+
raise CompilerError(f"Indexing non-array type: {base_t}")
|
|
1874
|
+
|
|
1875
|
+
# x0 = base pointer; 计算 elem 地址
|
|
1876
|
+
self.emit('MOV', self.reg(3), self.reg(0)) # x3 = base
|
|
1877
|
+
self.gen_value(idx_node) # x0 = index
|
|
1878
|
+
|
|
1879
|
+
# A1 --bounds-check: 定长数组索引 0 <= i < size
|
|
1880
|
+
if self._bounds and _is_fixed_array(base_t):
|
|
1881
|
+
size = base_t[2]
|
|
1882
|
+
l_ge = self.new_label('bndok')
|
|
1883
|
+
self.emit('CMP', self.reg(0), self.imm(0))
|
|
1884
|
+
self.emit('B', self.lab(l_ge), ('cond', 'GE'))
|
|
1885
|
+
self._runtime_abort("bounds-check: negative array index")
|
|
1886
|
+
self.label(l_ge)
|
|
1887
|
+
l_lt = self.new_label('bndok')
|
|
1888
|
+
self.emit('CMP', self.reg(0), self.imm(size))
|
|
1889
|
+
self.emit('B', self.lab(l_lt), ('cond', 'LT'))
|
|
1890
|
+
self._runtime_abort(f"bounds-check: index >= length ({size})")
|
|
1891
|
+
self.label(l_lt)
|
|
1892
|
+
|
|
1893
|
+
scale = _type_slots(elem_t) * 8
|
|
1894
|
+
self.emit('MOV', self.reg(1), self.imm(scale))
|
|
1895
|
+
self.emit('MUL', self.reg(0), self.reg(1)) # x0 = index * scale
|
|
1896
|
+
self.emit('ADD', self.reg(0), self.reg(3)) # x0 = elem 地址
|
|
1897
|
+
|
|
1898
|
+
if lvalue:
|
|
1899
|
+
return None
|
|
1900
|
+
|
|
1901
|
+
if _is_fixed_array(elem_t):
|
|
1902
|
+
return elem_t # 子数组: 值 = 地址
|
|
1903
|
+
if _is_ptr_array(elem_t):
|
|
1904
|
+
# 行指针 (int[][] 的 a[i]): 若为空则延迟分配 64 元素行
|
|
1905
|
+
self.emit('MOV', self.reg(5), self.reg(0)) # x5 = elem 地址
|
|
1906
|
+
self.emit('LD', self.reg(1), ('mem', 5, 0)) # x1 = 行指针
|
|
1907
|
+
l_done = self.new_label('rowdone')
|
|
1908
|
+
self.emit('CMP', self.reg(1), self.imm(0))
|
|
1909
|
+
self.emit('B', self.lab(l_done), ('cond', 'NE'))
|
|
1910
|
+
self.emit('MOV', self.reg(0), self.imm(64 * 8))
|
|
1911
|
+
self.emit('SYS', self.imm(Syscall.MALLOC))
|
|
1912
|
+
self.emit('MOV', self.reg(1), self.reg(0)) # x1 = 新行指针
|
|
1913
|
+
self.emit('SD', self.reg(1), ('mem', 5, 0)) # 写回 elem 槽
|
|
1914
|
+
self.label(l_done)
|
|
1915
|
+
self.emit('MOV', self.reg(0), self.reg(1))
|
|
1916
|
+
return elem_t
|
|
1917
|
+
# 标量元素
|
|
1918
|
+
self.emit('LD', self.reg(0), ('mem', 0, 0))
|
|
1919
|
+
return elem_t
|
|
1920
|
+
|
|
1921
|
+
# ---------------- 赋值 (在 gen_value 中拦截 binop '=') ----------------
|
|
1922
|
+
|
|
1923
|
+
def _gen_assign(self, target, value_node):
|
|
1924
|
+
vt = self.gen_value(value_node)
|
|
1925
|
+
# 目标类型
|
|
1926
|
+
tt = self._expr_type(target)
|
|
1927
|
+
self._convert(vt, tt)
|
|
1928
|
+
self.emit('MOV', self.reg(2), self.reg(0)) # value
|
|
1929
|
+
self._gen_lvalue_addr(target) # x0 = addr
|
|
1930
|
+
self.emit('SD', self.reg(2), ('mem', 0, 0))
|
|
1931
|
+
return tt
|
|
1932
|
+
|
|
1933
|
+
def _expr_type(self, node):
|
|
1934
|
+
kind = node[0]
|
|
1935
|
+
if kind == 'var':
|
|
1936
|
+
return self._var_type(node[1])
|
|
1937
|
+
if kind == 'member':
|
|
1938
|
+
obj_t = self._expr_type(node[1])
|
|
1939
|
+
if _is_struct(obj_t):
|
|
1940
|
+
ftype, _ = self._struct_field(obj_t, node[2])
|
|
1941
|
+
return ftype
|
|
1942
|
+
if kind == 'index':
|
|
1943
|
+
base_t = self._expr_type(node[1])
|
|
1944
|
+
if base_t == 'string':
|
|
1945
|
+
return 'int'
|
|
1946
|
+
elem = _array_elem(base_t) if _is_fixed_array(base_t) or _is_ptr_array(base_t) else None
|
|
1947
|
+
if _is_fixed_array(elem):
|
|
1948
|
+
return elem
|
|
1949
|
+
return elem
|
|
1950
|
+
if kind == 'call':
|
|
1951
|
+
f = self.functions.get(node[1])
|
|
1952
|
+
if f:
|
|
1953
|
+
return f.ret_type
|
|
1954
|
+
if node[1] in ('min', 'max'):
|
|
1955
|
+
at = self._expr_type(node[2][0])
|
|
1956
|
+
bt = self._expr_type(node[2][1])
|
|
1957
|
+
return 'float' if (at == 'float' or bt == 'float') else 'int'
|
|
1958
|
+
return self._builtin_ret_type(node[1])
|
|
1959
|
+
if kind == 'num':
|
|
1960
|
+
return 'float' if node[2] else 'int'
|
|
1961
|
+
if kind == 'bool':
|
|
1962
|
+
return 'bool'
|
|
1963
|
+
if kind == 'str':
|
|
1964
|
+
return 'string'
|
|
1965
|
+
if kind == 'binop':
|
|
1966
|
+
if node[1] in ('+=', '-=', '*=', '/=', '%=',
|
|
1967
|
+
'&=', '|=', '^=', '<<=', '>>='):
|
|
1968
|
+
return self._expr_type(node[2])
|
|
1969
|
+
if node[1] in ('&', '|', '^', '<<', '>>'):
|
|
1970
|
+
return 'int'
|
|
1971
|
+
if node[1] in ('+', '-', '*', '%'):
|
|
1972
|
+
lt = self._expr_type(node[2])
|
|
1973
|
+
rt = self._expr_type(node[3])
|
|
1974
|
+
if lt == 'string' or rt == 'string':
|
|
1975
|
+
return 'string'
|
|
1976
|
+
return 'float' if lt == 'float' or rt == 'float' else 'int'
|
|
1977
|
+
if node[1] == '/':
|
|
1978
|
+
return 'float'
|
|
1979
|
+
if node[1] in ('==', '!=', '<', '>', '<=', '>=', '&&', '||'):
|
|
1980
|
+
return 'bool'
|
|
1981
|
+
if kind == 'cond':
|
|
1982
|
+
lt = self._expr_type(node[2])
|
|
1983
|
+
rt = self._expr_type(node[3])
|
|
1984
|
+
if (lt == 'string') != (rt == 'string'):
|
|
1985
|
+
return 'int'
|
|
1986
|
+
return 'string' if lt == 'string' else \
|
|
1987
|
+
('float' if lt == 'float' or rt == 'float' else 'int')
|
|
1988
|
+
if kind in ('preinc', 'predec', 'postinc', 'postdec'):
|
|
1989
|
+
return self._expr_type(node[1])
|
|
1990
|
+
if kind == 'neg':
|
|
1991
|
+
it = self._expr_type(node[1])
|
|
1992
|
+
return 'float' if it == 'float' else 'int'
|
|
1993
|
+
if kind == 'not':
|
|
1994
|
+
return 'bool'
|
|
1995
|
+
if kind == 'bitnot':
|
|
1996
|
+
return 'int'
|
|
1997
|
+
return None
|
|
1998
|
+
|
|
1999
|
+
# ---------------- 二元运算 ----------------
|
|
2000
|
+
|
|
2001
|
+
def _gen_binop(self, op, left, right):
|
|
2002
|
+
if op == '=':
|
|
2003
|
+
return self._gen_assign(left, right)
|
|
2004
|
+
if op in _COMPOUND_TO_BASE:
|
|
2005
|
+
return self._gen_compound(left, _COMPOUND_TO_BASE[op], right)
|
|
2006
|
+
if op == '&&' or op == '||':
|
|
2007
|
+
return self._gen_logical(op, left, right)
|
|
2008
|
+
if op in ('&', '|', '^', '<<', '>>'):
|
|
2009
|
+
return self._gen_bitwise(op, left, right)
|
|
2010
|
+
if op in ('==', '!=', '<', '>', '<=', '>='):
|
|
2011
|
+
# 比较作为值表达式: 条件成立得 1, 否则 0
|
|
2012
|
+
l_false = self.new_label('cmpf')
|
|
2013
|
+
l_end = self.new_label('cmpe')
|
|
2014
|
+
self.gen_cond_jump_false(('binop', op, left, right), l_false)
|
|
2015
|
+
self.emit('MOV', self.reg(0), self.imm(1))
|
|
2016
|
+
self.emit('JMP', self.lab(l_end))
|
|
2017
|
+
self.label(l_false)
|
|
2018
|
+
self.emit('MOV', self.reg(0), self.imm(0))
|
|
2019
|
+
self.label(l_end)
|
|
2020
|
+
return 'bool'
|
|
2021
|
+
|
|
2022
|
+
lt = self._expr_type(left)
|
|
2023
|
+
rt = self._expr_type(right)
|
|
2024
|
+
if op == '+' and (lt == 'string' or rt == 'string'):
|
|
2025
|
+
self._gen_string_value(left)
|
|
2026
|
+
self.emit('PUSH', self.reg(0))
|
|
2027
|
+
self._gen_string_value(right)
|
|
2028
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2029
|
+
self.emit('POP', self.reg(0))
|
|
2030
|
+
self.emit('SYS', self.imm(Syscall.STR_CONCAT))
|
|
2031
|
+
return 'string'
|
|
2032
|
+
|
|
2033
|
+
float_mode = (lt == 'float' or rt == 'float') or op == '/'
|
|
2034
|
+
# 左操作数
|
|
2035
|
+
self.gen_value(left)
|
|
2036
|
+
if float_mode and lt == 'int':
|
|
2037
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2038
|
+
if float_mode and lt == 'bool':
|
|
2039
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2040
|
+
self.emit('PUSH', self.reg(0))
|
|
2041
|
+
# 右操作数
|
|
2042
|
+
self.gen_value(right)
|
|
2043
|
+
if float_mode and rt in ('int', 'bool'):
|
|
2044
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2045
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2046
|
+
self.emit('POP', self.reg(0))
|
|
2047
|
+
|
|
2048
|
+
if float_mode:
|
|
2049
|
+
sys_map = {'+': Syscall.FADD, '-': Syscall.FSUB,
|
|
2050
|
+
'*': Syscall.FMUL, '/': Syscall.FDIV}
|
|
2051
|
+
if op == '%':
|
|
2052
|
+
raise CompilerError("Float modulo not supported")
|
|
2053
|
+
self.emit('SYS', self.imm(sys_map[op]))
|
|
2054
|
+
return 'float'
|
|
2055
|
+
|
|
2056
|
+
if op == '%':
|
|
2057
|
+
# x0 = a - (a/b)*b
|
|
2058
|
+
self.emit('MOV', self.reg(2), self.reg(1)) # b
|
|
2059
|
+
self.emit('PUSH', self.reg(0)) # a
|
|
2060
|
+
self.emit('DIV', self.reg(0), self.reg(2)) # a/b
|
|
2061
|
+
self.emit('MUL', self.reg(0), self.reg(2)) # (a/b)*b
|
|
2062
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2063
|
+
self.emit('POP', self.reg(0))
|
|
2064
|
+
self.emit('SUB', self.reg(0), self.reg(1))
|
|
2065
|
+
return 'int'
|
|
2066
|
+
|
|
2067
|
+
op_map = {'+': 'ADD', '-': 'SUB', '*': 'MUL'}
|
|
2068
|
+
if op not in op_map:
|
|
2069
|
+
raise CompilerError(f"Unsupported int operator: {op}")
|
|
2070
|
+
self.emit(op_map[op], self.reg(0), self.reg(1))
|
|
2071
|
+
return 'int'
|
|
2072
|
+
|
|
2073
|
+
def _gen_logical(self, op, left, right):
|
|
2074
|
+
l_true = self.new_label('lt')
|
|
2075
|
+
l_false = self.new_label('lf')
|
|
2076
|
+
l_end = self.new_label('le')
|
|
2077
|
+
if op == '&&':
|
|
2078
|
+
self.gen_cond_jump_false(left, l_false)
|
|
2079
|
+
self.gen_cond_jump_false(right, l_false)
|
|
2080
|
+
else: # ||
|
|
2081
|
+
self.gen_cond_jump_true(left, l_true)
|
|
2082
|
+
self.gen_cond_jump_true(right, l_true)
|
|
2083
|
+
self.emit('JMP', self.lab(l_false))
|
|
2084
|
+
self.label(l_true)
|
|
2085
|
+
self.emit('MOV', self.reg(0), self.imm(1))
|
|
2086
|
+
self.emit('JMP', self.lab(l_end))
|
|
2087
|
+
self.label(l_false)
|
|
2088
|
+
self.emit('MOV', self.reg(0), self.imm(0))
|
|
2089
|
+
self.label(l_end)
|
|
2090
|
+
return 'bool'
|
|
2091
|
+
|
|
2092
|
+
def _gen_bitwise(self, op, left, right) -> Any:
|
|
2093
|
+
"""位运算 & | ^ << >> (整数); >> 为算术右移 (保留符号)。"""
|
|
2094
|
+
lt = self._expr_type(left)
|
|
2095
|
+
rt = self._expr_type(right)
|
|
2096
|
+
if lt in ('float', 'string') or rt in ('float', 'string'):
|
|
2097
|
+
raise CompilerError(
|
|
2098
|
+
f"Bitwise operator '{op}' requires integer operands "
|
|
2099
|
+
f"(got {lt} and {rt})")
|
|
2100
|
+
self.gen_value(left)
|
|
2101
|
+
self.emit('PUSH', self.reg(0))
|
|
2102
|
+
self.gen_value(right)
|
|
2103
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2104
|
+
self.emit('POP', self.reg(0))
|
|
2105
|
+
if op == '&':
|
|
2106
|
+
self.emit('AND', self.reg(0), self.reg(1))
|
|
2107
|
+
elif op == '|':
|
|
2108
|
+
self.emit('OR', self.reg(0), self.reg(1))
|
|
2109
|
+
elif op == '^':
|
|
2110
|
+
self.emit('XOR', self.reg(0), self.reg(1))
|
|
2111
|
+
elif op == '<<':
|
|
2112
|
+
self.emit('SHL', self.reg(0), self.reg(1))
|
|
2113
|
+
else: # '>>'
|
|
2114
|
+
self.emit('ASR', self.reg(0), self.reg(0), self.reg(1))
|
|
2115
|
+
return 'int'
|
|
2116
|
+
|
|
2117
|
+
# ---------------- 复合赋值 / 自增自减 / 三目 ----------------
|
|
2118
|
+
|
|
2119
|
+
def _gen_compound(self, target, op: str, value_node) -> Any:
|
|
2120
|
+
"""target op= value (op ∈ + - * / % & | ^ << >>); 左值地址只求值一次。"""
|
|
2121
|
+
tt = self._expr_type(target)
|
|
2122
|
+
if tt not in ('int', 'bool', 'float'):
|
|
2123
|
+
raise CompilerError(f"Cannot apply '{op}=' to type: {tt}")
|
|
2124
|
+
if tt == 'float' and op not in ('+', '-', '*', '/'):
|
|
2125
|
+
raise CompilerError(f"Cannot apply '{op}=' to float")
|
|
2126
|
+
float_mode = tt == 'float'
|
|
2127
|
+
|
|
2128
|
+
self._gen_lvalue_addr(target)
|
|
2129
|
+
self.emit('PUSH', self.reg(0)) # [SP] = addr
|
|
2130
|
+
vt = self.gen_value(value_node) # x0 = rhs
|
|
2131
|
+
self._convert(vt, tt)
|
|
2132
|
+
self.emit('MOV', self.reg(1), self.reg(0)) # b = rhs
|
|
2133
|
+
self.emit('LD', self.reg(2), ('mem', 32, 0)) # x2 = addr
|
|
2134
|
+
self.emit('LD', self.reg(0), ('mem', 2, 0)) # a = old
|
|
2135
|
+
|
|
2136
|
+
if float_mode:
|
|
2137
|
+
fmap = {'+': Syscall.FADD, '-': Syscall.FSUB,
|
|
2138
|
+
'*': Syscall.FMUL, '/': Syscall.FDIV}
|
|
2139
|
+
self.emit('SYS', self.imm(fmap[op]))
|
|
2140
|
+
elif op == '+':
|
|
2141
|
+
self.emit('ADD', self.reg(0), self.reg(1))
|
|
2142
|
+
elif op == '-':
|
|
2143
|
+
self.emit('SUB', self.reg(0), self.reg(1))
|
|
2144
|
+
elif op == '*':
|
|
2145
|
+
self.emit('MUL', self.reg(0), self.reg(1))
|
|
2146
|
+
elif op == '/':
|
|
2147
|
+
self.emit('DIV', self.reg(0), self.reg(1))
|
|
2148
|
+
elif op == '%':
|
|
2149
|
+
self.emit('MOV', self.reg(3), self.reg(1)) # 除数备份
|
|
2150
|
+
self.emit('PUSH', self.reg(0))
|
|
2151
|
+
self.emit('DIV', self.reg(0), self.reg(3))
|
|
2152
|
+
self.emit('MUL', self.reg(0), self.reg(3))
|
|
2153
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2154
|
+
self.emit('POP', self.reg(0))
|
|
2155
|
+
self.emit('SUB', self.reg(0), self.reg(1))
|
|
2156
|
+
elif op == '&':
|
|
2157
|
+
self.emit('AND', self.reg(0), self.reg(1))
|
|
2158
|
+
elif op == '|':
|
|
2159
|
+
self.emit('OR', self.reg(0), self.reg(1))
|
|
2160
|
+
elif op == '^':
|
|
2161
|
+
self.emit('XOR', self.reg(0), self.reg(1))
|
|
2162
|
+
elif op == '<<':
|
|
2163
|
+
self.emit('SHL', self.reg(0), self.reg(1))
|
|
2164
|
+
elif op == '>>':
|
|
2165
|
+
self.emit('ASR', self.reg(0), self.reg(0), self.reg(1))
|
|
2166
|
+
else:
|
|
2167
|
+
raise CompilerError(f"Unsupported compound operator: {op}=")
|
|
2168
|
+
|
|
2169
|
+
self.emit('SD', self.reg(0), ('mem', 2, 0))
|
|
2170
|
+
self.emit('ADDI', self.reg(32), self.reg(32), self.imm(8))
|
|
2171
|
+
return tt
|
|
2172
|
+
|
|
2173
|
+
def _gen_incdec(self, kind: str, target) -> Any:
|
|
2174
|
+
"""++/-- (前缀与后缀); 后缀返回旧值, 前缀返回新值。"""
|
|
2175
|
+
tt = self._expr_type(target)
|
|
2176
|
+
if tt not in ('int', 'bool', 'float'):
|
|
2177
|
+
raise CompilerError(f"Cannot {kind} value of type: {tt}")
|
|
2178
|
+
op = '+' if 'inc' in kind else '-'
|
|
2179
|
+
postfix = kind.startswith('post')
|
|
2180
|
+
float_mode = tt == 'float'
|
|
2181
|
+
|
|
2182
|
+
self._gen_lvalue_addr(target)
|
|
2183
|
+
self.emit('PUSH', self.reg(0)) # [SP] = addr
|
|
2184
|
+
self.emit('LD', self.reg(2), ('mem', 32, 0)) # x2 = addr
|
|
2185
|
+
self.emit('LD', self.reg(0), ('mem', 2, 0)) # a = old
|
|
2186
|
+
if postfix:
|
|
2187
|
+
self.emit('MOV', self.reg(5), self.reg(0)) # 保存旧值
|
|
2188
|
+
if float_mode:
|
|
2189
|
+
self.emit('MOV', self.reg(0), self.imm(1))
|
|
2190
|
+
self.emit('SYS', self.imm(Syscall.ITOF)) # b = 1.0
|
|
2191
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2192
|
+
self.emit('LD', self.reg(0), ('mem', 2, 0)) # a 回填
|
|
2193
|
+
self.emit('SYS', self.imm(Syscall.FADD if op == '+'
|
|
2194
|
+
else Syscall.FSUB))
|
|
2195
|
+
else:
|
|
2196
|
+
self.emit('MOV', self.reg(1), self.imm(1))
|
|
2197
|
+
self.emit('ADD' if op == '+' else 'SUB',
|
|
2198
|
+
self.reg(0), self.reg(1))
|
|
2199
|
+
self.emit('SD', self.reg(0), ('mem', 2, 0))
|
|
2200
|
+
self.emit('ADDI', self.reg(32), self.reg(32), self.imm(8))
|
|
2201
|
+
if postfix:
|
|
2202
|
+
self.emit('MOV', self.reg(0), self.reg(5))
|
|
2203
|
+
return tt
|
|
2204
|
+
|
|
2205
|
+
def _gen_minmax(self, name: str, args) -> Any:
|
|
2206
|
+
"""min/max(a, b): int/float 数值最值 (bool 视作 int)。"""
|
|
2207
|
+
at = self._expr_type(args[0])
|
|
2208
|
+
bt = self._expr_type(args[1])
|
|
2209
|
+
if at == 'string' or bt == 'string':
|
|
2210
|
+
raise CompilerError(f"{name} does not accept string operands")
|
|
2211
|
+
tt = 'float' if (at == 'float' or bt == 'float') else 'int'
|
|
2212
|
+
|
|
2213
|
+
self.gen_value(args[0])
|
|
2214
|
+
if tt == 'float' and at in ('int', 'bool'):
|
|
2215
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2216
|
+
self.emit('PUSH', self.reg(0)) # [SP] = a
|
|
2217
|
+
self.gen_value(args[1])
|
|
2218
|
+
if tt == 'float' and bt in ('int', 'bool'):
|
|
2219
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2220
|
+
self.emit('MOV', self.reg(1), self.reg(0)) # x1 = b
|
|
2221
|
+
self.emit('POP', self.reg(0)) # x0 = a
|
|
2222
|
+
|
|
2223
|
+
# min: a<=b 取 a; max: a>=b 取 a
|
|
2224
|
+
cond = 'LE' if name == 'min' else 'GE'
|
|
2225
|
+
if tt == 'float':
|
|
2226
|
+
self.emit('MOV', self.reg(2), self.reg(0)) # 备份 a
|
|
2227
|
+
self.emit('MOV', self.reg(3), self.reg(1)) # 备份 b
|
|
2228
|
+
self.emit('SYS', self.imm(Syscall.FCMP)) # x0 = cmp(a,b) ∈ {-1,0,1}
|
|
2229
|
+
self.emit('CMP', self.reg(0), self.imm(0))
|
|
2230
|
+
l_keep = self.new_label('mmkeep')
|
|
2231
|
+
l_done = self.new_label('mmdone')
|
|
2232
|
+
self.emit('B', self.lab(l_keep), ('cond', cond))
|
|
2233
|
+
self.emit('MOV', self.reg(0), self.reg(3)) # result = b
|
|
2234
|
+
self.emit('JMP', self.lab(l_done))
|
|
2235
|
+
self.label(l_keep)
|
|
2236
|
+
self.emit('MOV', self.reg(0), self.reg(2)) # result = a
|
|
2237
|
+
self.label(l_done)
|
|
2238
|
+
else:
|
|
2239
|
+
self.emit('CMP', self.reg(0), self.reg(1))
|
|
2240
|
+
l_keep = self.new_label('mmkeep')
|
|
2241
|
+
self.emit('B', self.lab(l_keep), ('cond', cond))
|
|
2242
|
+
self.emit('MOV', self.reg(0), self.reg(1)) # result = b
|
|
2243
|
+
self.label(l_keep)
|
|
2244
|
+
return tt
|
|
2245
|
+
|
|
2246
|
+
def _gen_ternary(self, cond, a, b) -> Any:
|
|
2247
|
+
lt = self._expr_type(a)
|
|
2248
|
+
rt = self._expr_type(b)
|
|
2249
|
+
if (lt == 'string') != (rt == 'string'):
|
|
2250
|
+
raise CompilerError("Cannot mix string and numeric in '?:'")
|
|
2251
|
+
tt = 'string' if lt == 'string' else \
|
|
2252
|
+
('float' if (lt == 'float' or rt == 'float') else 'int')
|
|
2253
|
+
l_false = self.new_label('cndf')
|
|
2254
|
+
l_end = self.new_label('cnde')
|
|
2255
|
+
self.gen_cond_jump_false(cond, l_false)
|
|
2256
|
+
t1 = self.gen_value(a)
|
|
2257
|
+
self._convert(t1, tt)
|
|
2258
|
+
self.emit('MOV', self.reg(6), self.reg(0))
|
|
2259
|
+
self.emit('JMP', self.lab(l_end))
|
|
2260
|
+
self.label(l_false)
|
|
2261
|
+
t2 = self.gen_value(b)
|
|
2262
|
+
self._convert(t2, tt)
|
|
2263
|
+
self.emit('MOV', self.reg(6), self.reg(0))
|
|
2264
|
+
self.label(l_end)
|
|
2265
|
+
self.emit('MOV', self.reg(0), self.reg(6))
|
|
2266
|
+
return tt
|
|
2267
|
+
|
|
2268
|
+
# ---------------- 字符串化 (print/concat) ----------------
|
|
2269
|
+
|
|
2270
|
+
def _gen_string_value(self, node) -> None:
|
|
2271
|
+
"""求值表达式并将 x0 转为字符串指针。"""
|
|
2272
|
+
t = self.gen_value(node)
|
|
2273
|
+
if t == 'string':
|
|
2274
|
+
return
|
|
2275
|
+
if t == 'float':
|
|
2276
|
+
self.emit('SYS', self.imm(Syscall.FTOA))
|
|
2277
|
+
elif t == 'bool':
|
|
2278
|
+
self.emit('SYS', self.imm(Syscall.BOOL_STR))
|
|
2279
|
+
else:
|
|
2280
|
+
self.emit('SYS', self.imm(Syscall.ITOA))
|
|
2281
|
+
|
|
2282
|
+
def gen_print(self, node, newline: bool) -> None:
|
|
2283
|
+
t = self.gen_value(node)
|
|
2284
|
+
if t == 'string':
|
|
2285
|
+
pass
|
|
2286
|
+
elif t == 'float':
|
|
2287
|
+
self.emit('SYS', self.imm(Syscall.FTOA))
|
|
2288
|
+
elif t == 'bool':
|
|
2289
|
+
self.emit('SYS', self.imm(Syscall.BOOL_STR))
|
|
2290
|
+
else:
|
|
2291
|
+
self.emit('SYS', self.imm(Syscall.ITOA))
|
|
2292
|
+
self.emit('SYS', self.imm(Syscall.PRINT_STR))
|
|
2293
|
+
if newline:
|
|
2294
|
+
self.emit('OUT', self.imm(10))
|
|
2295
|
+
|
|
2296
|
+
# ---------------- 函数调用 ----------------
|
|
2297
|
+
|
|
2298
|
+
def _builtin_ret_type(self, name: str):
|
|
2299
|
+
host = HOST_BUILTINS.get(name)
|
|
2300
|
+
if host is not None:
|
|
2301
|
+
return None if host[2] == 'void' else host[2]
|
|
2302
|
+
if name in ('sin', 'cos', 'tan', 'sqrt', 'pow', 'floor', 'ceil', 'round'):
|
|
2303
|
+
return 'float'
|
|
2304
|
+
if name in ('strlen', 'strcmp', 'rand', 'time', 'abs', 'input',
|
|
2305
|
+
'idiv', 'atoi'):
|
|
2306
|
+
return 'int'
|
|
2307
|
+
if name in ('strcpy', 'int_to_str', 'itoa', 'float_to_str', 'ftoa',
|
|
2308
|
+
'bool_to_str', 'substr', 'upper', 'lower',
|
|
2309
|
+
'trim', 'ltrim', 'rtrim'):
|
|
2310
|
+
return 'string'
|
|
2311
|
+
return None
|
|
2312
|
+
|
|
2313
|
+
def _gen_host_sys(self, sys_id: int, args: list) -> None:
|
|
2314
|
+
"""求值 args (左到右) 并放入 x0..x(n-1), 发射 SYS sys_id。"""
|
|
2315
|
+
for a in args:
|
|
2316
|
+
self.gen_value(a)
|
|
2317
|
+
self.emit('PUSH', self.reg(0))
|
|
2318
|
+
for i in range(len(args) - 1, -1, -1):
|
|
2319
|
+
self.emit('POP', self.reg(i))
|
|
2320
|
+
self.emit('SYS', self.imm(sys_id))
|
|
2321
|
+
|
|
2322
|
+
def _gen_call(self, name: str, args: list):
|
|
2323
|
+
min_args = BUILTIN_MIN_ARGS.get(name)
|
|
2324
|
+
if min_args is not None and len(args) < min_args:
|
|
2325
|
+
raise CompilerError(
|
|
2326
|
+
f"{name}() expects at least {min_args} argument(s), "
|
|
2327
|
+
f"got {len(args)}")
|
|
2328
|
+
if name in ('println', 'print'):
|
|
2329
|
+
# 单参数 (拼接由表达式完成)
|
|
2330
|
+
if args:
|
|
2331
|
+
self.gen_print(args[0], newline=(name == 'println'))
|
|
2332
|
+
else:
|
|
2333
|
+
self.emit('OUT', self.imm(10))
|
|
2334
|
+
return 'void'
|
|
2335
|
+
|
|
2336
|
+
math_unary = {'sqrt': Syscall.SQRT, 'sin': Syscall.SIN,
|
|
2337
|
+
'cos': Syscall.COS, 'tan': Syscall.TAN}
|
|
2338
|
+
if name in math_unary:
|
|
2339
|
+
at = self.gen_value(args[0])
|
|
2340
|
+
if at == 'int':
|
|
2341
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2342
|
+
self.emit('SYS', self.imm(math_unary[name]))
|
|
2343
|
+
return 'float'
|
|
2344
|
+
|
|
2345
|
+
round_unary = {'floor': Syscall.FLOOR, 'ceil': Syscall.CEIL,
|
|
2346
|
+
'round': Syscall.ROUND}
|
|
2347
|
+
if name in round_unary:
|
|
2348
|
+
at = self.gen_value(args[0])
|
|
2349
|
+
if at in ('int', 'bool'):
|
|
2350
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2351
|
+
self.emit('SYS', self.imm(round_unary[name]))
|
|
2352
|
+
return 'float'
|
|
2353
|
+
|
|
2354
|
+
if name in ('min', 'max'):
|
|
2355
|
+
return self._gen_minmax(name, args)
|
|
2356
|
+
|
|
2357
|
+
if name == 'idiv':
|
|
2358
|
+
at = self._expr_type(args[0])
|
|
2359
|
+
bt = self._expr_type(args[1])
|
|
2360
|
+
if at in ('float', 'string') or bt in ('float', 'string'):
|
|
2361
|
+
raise CompilerError("idiv requires integer operands")
|
|
2362
|
+
self.gen_value(args[0])
|
|
2363
|
+
self.emit('PUSH', self.reg(0))
|
|
2364
|
+
self.gen_value(args[1])
|
|
2365
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2366
|
+
self.emit('POP', self.reg(0))
|
|
2367
|
+
self.emit('DIV', self.reg(0), self.reg(1))
|
|
2368
|
+
return 'int'
|
|
2369
|
+
|
|
2370
|
+
if name == 'pow':
|
|
2371
|
+
self._arg_float(args[0])
|
|
2372
|
+
self.emit('PUSH', self.reg(0))
|
|
2373
|
+
self._arg_float(args[1])
|
|
2374
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2375
|
+
self.emit('POP', self.reg(0))
|
|
2376
|
+
self.emit('SYS', self.imm(Syscall.POW))
|
|
2377
|
+
return 'float'
|
|
2378
|
+
if name == 'abs':
|
|
2379
|
+
self.gen_value(args[0])
|
|
2380
|
+
self.emit('SYS', self.imm(Syscall.ABS))
|
|
2381
|
+
return 'int'
|
|
2382
|
+
if name == 'strlen':
|
|
2383
|
+
self.gen_value(args[0])
|
|
2384
|
+
self.emit('SYS', self.imm(Syscall.STRLEN))
|
|
2385
|
+
return 'int'
|
|
2386
|
+
if name == 'strcmp':
|
|
2387
|
+
self.gen_value(args[0])
|
|
2388
|
+
self.emit('PUSH', self.reg(0))
|
|
2389
|
+
self.gen_value(args[1])
|
|
2390
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2391
|
+
self.emit('POP', self.reg(0))
|
|
2392
|
+
self.emit('SYS', self.imm(Syscall.STRCMP))
|
|
2393
|
+
return 'int'
|
|
2394
|
+
if name == 'strcpy':
|
|
2395
|
+
self.gen_value(args[0])
|
|
2396
|
+
self.emit('PUSH', self.reg(0))
|
|
2397
|
+
self.emit('MOV', self.reg(0), self.imm(self._data_string("")))
|
|
2398
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2399
|
+
self.emit('POP', self.reg(0))
|
|
2400
|
+
self.emit('SYS', self.imm(Syscall.STR_CONCAT))
|
|
2401
|
+
return 'string'
|
|
2402
|
+
if name == 'rand':
|
|
2403
|
+
self.emit('SYS', self.imm(Syscall.RAND))
|
|
2404
|
+
return 'int'
|
|
2405
|
+
if name == 'srand':
|
|
2406
|
+
self.gen_value(args[0])
|
|
2407
|
+
self.emit('SYS', self.imm(Syscall.SRAND))
|
|
2408
|
+
return 'void'
|
|
2409
|
+
if name in ('int_to_str', 'itoa'):
|
|
2410
|
+
self.gen_value(args[0])
|
|
2411
|
+
self.emit('SYS', self.imm(Syscall.ITOA))
|
|
2412
|
+
return 'string'
|
|
2413
|
+
if name in ('float_to_str', 'ftoa'):
|
|
2414
|
+
t = self.gen_value(args[0])
|
|
2415
|
+
if t in ('int', 'bool'):
|
|
2416
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2417
|
+
self.emit('SYS', self.imm(Syscall.FTOA))
|
|
2418
|
+
return 'string'
|
|
2419
|
+
if name in ('bool_to_str',):
|
|
2420
|
+
self.gen_value(args[0])
|
|
2421
|
+
self.emit('SYS', self.imm(Syscall.BOOL_STR))
|
|
2422
|
+
return 'string'
|
|
2423
|
+
if name == 'substr':
|
|
2424
|
+
self._gen_string_value(args[0])
|
|
2425
|
+
self.emit('PUSH', self.reg(0))
|
|
2426
|
+
self.gen_value(args[1])
|
|
2427
|
+
self.emit('PUSH', self.reg(0))
|
|
2428
|
+
self.gen_value(args[2])
|
|
2429
|
+
self.emit('MOV', self.reg(2), self.reg(0))
|
|
2430
|
+
self.emit('POP', self.reg(1))
|
|
2431
|
+
self.emit('POP', self.reg(0))
|
|
2432
|
+
self.emit('SYS', self.imm(Syscall.SUBSTR))
|
|
2433
|
+
return 'string'
|
|
2434
|
+
if name == 'indexof':
|
|
2435
|
+
self._gen_string_value(args[0])
|
|
2436
|
+
self.emit('PUSH', self.reg(0))
|
|
2437
|
+
self._gen_string_value(args[1])
|
|
2438
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2439
|
+
self.emit('POP', self.reg(0))
|
|
2440
|
+
self.emit('SYS', self.imm(Syscall.INDEXOF))
|
|
2441
|
+
return 'int'
|
|
2442
|
+
if name in ('upper', 'lower'):
|
|
2443
|
+
self._gen_string_value(args[0])
|
|
2444
|
+
self.emit('SYS', self.imm(Syscall.TOUPPER if name == 'upper'
|
|
2445
|
+
else Syscall.TOLOWER))
|
|
2446
|
+
return 'string'
|
|
2447
|
+
if name in ('trim', 'ltrim', 'rtrim'):
|
|
2448
|
+
self._gen_string_value(args[0])
|
|
2449
|
+
sys_id = {'trim': Syscall.TRIM, 'ltrim': Syscall.LTRIM,
|
|
2450
|
+
'rtrim': Syscall.RTRIM}[name]
|
|
2451
|
+
self.emit('SYS', self.imm(sys_id))
|
|
2452
|
+
return 'string'
|
|
2453
|
+
if name == 'atoi':
|
|
2454
|
+
self.gen_value(args[0])
|
|
2455
|
+
self.emit('SYS', self.imm(Syscall.ATOI))
|
|
2456
|
+
return 'int'
|
|
2457
|
+
# ---- 宿主能力 (表驱动): 音频 / 画布 / 系统交互 / Termux API ----
|
|
2458
|
+
host = HOST_BUILTINS.get(name)
|
|
2459
|
+
if host is not None:
|
|
2460
|
+
sys_id, nargs, ret = host
|
|
2461
|
+
self._gen_host_sys(sys_id, args[:nargs])
|
|
2462
|
+
return ret
|
|
2463
|
+
if name == 'time':
|
|
2464
|
+
self.emit('SYS', self.imm(Syscall.TIME))
|
|
2465
|
+
return 'int'
|
|
2466
|
+
if name == 'input':
|
|
2467
|
+
self.emit('MOV', self.reg(0), self.imm(0))
|
|
2468
|
+
return 'int'
|
|
2469
|
+
|
|
2470
|
+
# 用户函数
|
|
2471
|
+
fdef = self.functions.get(name)
|
|
2472
|
+
if fdef is None:
|
|
2473
|
+
raise CompilerError(f"Unknown function: {name}")
|
|
2474
|
+
for k, arg in enumerate(args):
|
|
2475
|
+
at = self.gen_value(arg)
|
|
2476
|
+
ptype = fdef.params[k][1] if k < len(fdef.params) else None
|
|
2477
|
+
self._convert(at, self._param_promote(ptype))
|
|
2478
|
+
self.emit('PUSH', self.reg(0))
|
|
2479
|
+
self.emit('CALL', self.lab(name))
|
|
2480
|
+
# 调用方清理参数 (不得使用 x0, 它持有返回值)
|
|
2481
|
+
nargs = len(args)
|
|
2482
|
+
if nargs:
|
|
2483
|
+
self.emit('ADDI', self.reg(6), self.reg(32), self.imm(nargs * 8))
|
|
2484
|
+
self.emit('MOV', self.reg(32), self.reg(6))
|
|
2485
|
+
return fdef.ret_type
|
|
2486
|
+
|
|
2487
|
+
@staticmethod
|
|
2488
|
+
def _param_promote(ptype):
|
|
2489
|
+
# 数组参数衰减
|
|
2490
|
+
if _is_fixed_array(ptype):
|
|
2491
|
+
return ('ptrarray', _array_elem(ptype))
|
|
2492
|
+
return ptype
|
|
2493
|
+
|
|
2494
|
+
def _arg_float(self, node) -> None:
|
|
2495
|
+
t = self.gen_value(node)
|
|
2496
|
+
if t == 'int' or t == 'bool':
|
|
2497
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2498
|
+
|
|
2499
|
+
# ---------------- 条件跳转 ----------------
|
|
2500
|
+
|
|
2501
|
+
_COND_FALSE_JUMP = {
|
|
2502
|
+
'==': 'NE', '!=': 'EQ',
|
|
2503
|
+
'<': 'GE', '>': 'LE',
|
|
2504
|
+
'<=': 'GT', '>=': 'LT',
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
def gen_cond_jump_false(self, node, label_false: str) -> None:
|
|
2508
|
+
kind = node[0]
|
|
2509
|
+
if kind == 'bool':
|
|
2510
|
+
if not node[1]:
|
|
2511
|
+
self.emit('JMP', self.lab(label_false))
|
|
2512
|
+
return
|
|
2513
|
+
if kind == 'binop' and node[1] == '&&':
|
|
2514
|
+
self.gen_cond_jump_false(node[2], label_false)
|
|
2515
|
+
self.gen_cond_jump_false(node[3], label_false)
|
|
2516
|
+
return
|
|
2517
|
+
if kind == 'binop' and node[1] == '||':
|
|
2518
|
+
l_true = self.new_label('ortrue')
|
|
2519
|
+
self.gen_cond_jump_true(node[2], l_true)
|
|
2520
|
+
self.gen_cond_jump_true(node[3], l_true)
|
|
2521
|
+
self.emit('JMP', self.lab(label_false))
|
|
2522
|
+
self.label(l_true)
|
|
2523
|
+
return
|
|
2524
|
+
if kind == 'not':
|
|
2525
|
+
self.gen_cond_jump_true(node[1], label_false)
|
|
2526
|
+
return
|
|
2527
|
+
if kind == 'binop' and node[1] in self._COND_FALSE_JUMP:
|
|
2528
|
+
op = node[1]
|
|
2529
|
+
lt = self._expr_type(node[2])
|
|
2530
|
+
rt = self._expr_type(node[3])
|
|
2531
|
+
float_mode = lt == 'float' or rt == 'float'
|
|
2532
|
+
self.gen_value(node[2])
|
|
2533
|
+
if float_mode and lt in ('int', 'bool'):
|
|
2534
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2535
|
+
self.emit('PUSH', self.reg(0))
|
|
2536
|
+
self.gen_value(node[3])
|
|
2537
|
+
if float_mode and rt in ('int', 'bool'):
|
|
2538
|
+
self.emit('SYS', self.imm(Syscall.ITOF))
|
|
2539
|
+
self.emit('MOV', self.reg(1), self.reg(0))
|
|
2540
|
+
self.emit('POP', self.reg(0))
|
|
2541
|
+
if float_mode:
|
|
2542
|
+
self.emit('SYS', self.imm(Syscall.FCMP))
|
|
2543
|
+
self.emit('CMP', self.reg(0), self.imm(0))
|
|
2544
|
+
else:
|
|
2545
|
+
self.emit('CMP', self.reg(0), self.reg(1))
|
|
2546
|
+
self.emit('B', self.lab(label_false),
|
|
2547
|
+
('cond', self._COND_FALSE_JUMP[op]))
|
|
2548
|
+
return
|
|
2549
|
+
# 普通布尔值
|
|
2550
|
+
self.gen_value(node)
|
|
2551
|
+
self.emit('CMP', self.reg(0), self.imm(0))
|
|
2552
|
+
self.emit('JZ', self.lab(label_false))
|
|
2553
|
+
|
|
2554
|
+
def gen_cond_jump_true(self, node, label_true: str) -> None:
|
|
2555
|
+
l_false = self.new_label('cf')
|
|
2556
|
+
self.gen_cond_jump_false(node, l_false)
|
|
2557
|
+
self.emit('JMP', self.lab(label_true))
|
|
2558
|
+
self.label(l_false)
|