去除 import t, c
This commit is contained in:
1 parent
85b89b6e8d
commit
b90a8a7bfb
17 files changed
+163
-862
No files matched your search
@@ -27,7 +27,7 @@ import vthreading
|
||||
import requests
|
||||
import requests.https as rhttps
|
||||
import json
|
||||
import w32.win32memory as win32mem
|
||||
import win32.win32memory as win32mem
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
+51
-57
@@ -1,22 +1,22 @@
|
||||
# ============================================================
|
||||
# main.vp — ViperCPW:CreateProcessA 独立复现工程
|
||||
#
|
||||
# 目的:把原先塞在 TransPyV\App\main.vp 里的 [TEMP-PROBE] 探针整体搬到
|
||||
# 一个独立 Viper 工程里,脱开 TPV 单独复现 / 二分。
|
||||
# 目的:把原先塞在 ViperC\App\main.vp 里的 [TEMP-PROBE] 探针整体搬到
|
||||
# 一个独立 Viper 工程里,脱开 VPC 单独复现 / 二分。
|
||||
#
|
||||
# 待复现现象:自举出的 TransPyV.exe 内 CreateProcessA 恒返回 0 且
|
||||
# 待复现现象:自举出的 viperc.exe 内 CreateProcessA 恒返回 0 且
|
||||
# GetLastError=87(ERROR_INVALID_PARAMETER);同参数在 Python/ctypes
|
||||
# 下 ok=1。
|
||||
#
|
||||
# TPV 侧已逐项实测 ok=0/err=87 的维度(本工程用于在"非 TPV 宿主"上复核):
|
||||
# VPC 侧已逐项实测 ok=0/err=87 的维度(本工程用于在"非 VPC 宿主"上复核):
|
||||
# IR/机器码栈传参(逐槽核对正确)、si.cb=104 与结构体布局、命令行内容
|
||||
# (逐字节回读正确、手工复制不用 strcpy 也 87)、应用名(含绝对路径)、
|
||||
# lpCurrentDirectory、lpEnvironment、bInheritHandles(0/1)、
|
||||
# dwCreationFlags(0/CREATE_NO_WINDOW)。
|
||||
#
|
||||
# 本工程要回答的问题:这是"仅 TPV.exe 特有",还是"任何 Viper 程序都如此"。
|
||||
# 本工程要回答的问题:这是"仅 VPC.exe 特有",还是"任何 Viper 程序都如此"。
|
||||
#
|
||||
# 五组用例(与 TPV 探针同参数、同 si 构造),每组打印 ok 与 GetLastError:
|
||||
# 五组用例(与 VPC 探针同参数、同 si 构造),每组打印 ok 与 GetLastError:
|
||||
# #1 lpApplicationName=NULL + "llc --version",inh=1,flags=0
|
||||
# #2 同 #1 但 inh=0
|
||||
# #3 同 #1 但 flags=CREATE_NO_WINDOW
|
||||
@@ -25,19 +25,18 @@
|
||||
# 对照组:打印本进程 GetCurrentDirectoryA 的结果(证明本进程能正常调 Win32)。
|
||||
#
|
||||
# 判定:
|
||||
# 五组全 ok=0/err=87 ⇒ 与 TransPyV.exe 同因,问题在 Viper 生成代码/运行期,
|
||||
# 与 TPV 自身逻辑无关(任何 Viper 程序都如此)。
|
||||
# 任一组 ok=1 ⇒ 该维度即是 TPV 特有问题,按组二分定位。
|
||||
# 五组全 ok=0/err=87 ⇒ 与 viperc.exe 同因,问题在 Viper 生成代码/运行期,
|
||||
# 与 VPC 自身逻辑无关(任何 Viper 程序都如此)。
|
||||
# 任一组 ok=1 ⇒ 该维度即是 VPC 特有问题,按组二分定位。
|
||||
# ============================================================
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import stdlib
|
||||
import string
|
||||
import w32.win32base
|
||||
import w32.win32file
|
||||
import w32.win32process
|
||||
import w32.win32console
|
||||
import win32.win32base
|
||||
import win32.win32file
|
||||
import win32.win32process
|
||||
import win32.win32console
|
||||
|
||||
|
||||
# 控制台代码页:UTF-8
|
||||
@@ -47,7 +46,7 @@ define PAGE_CODE = 65001
|
||||
|
||||
# ============================================================
|
||||
# 单组复现:构造 si/pi → 调 CreateProcessA → 打印 ok / GetLastError / si 字段
|
||||
# si 构造与 TPV 的 _run_cmd_wait 逐字一致:
|
||||
# si 构造与 VPC 的 _run_cmd_wait 逐字一致:
|
||||
# T() 构造 → string.memset 显式清零 → si.cb = STARTUPINFOA.__sizeof__()
|
||||
# ============================================================
|
||||
def ProbeCreateProcessA(Tag: str, AppName: str, CommandLine: str,
|
||||
@@ -59,7 +58,7 @@ def ProbeCreateProcessA(Tag: str, AppName: str, CommandLine: str,
|
||||
CommandLine : lpCommandLine
|
||||
InheritHandles : 第 5 实参 bInheritHandles
|
||||
CreationFlags : 第 6 实参 dwCreationFlags
|
||||
lpEnvironment / lpCurrentDirectory 恒传 NULL(TPV 侧已实测与 87 无关)。
|
||||
lpEnvironment / lpCurrentDirectory 恒传 NULL(VPC 侧已实测与 87 无关)。
|
||||
"""
|
||||
# 命令行必须放进可写堆缓冲:CreateProcessA 会原地改写 lpCommandLine,
|
||||
# 不能传只读字面量。
|
||||
@@ -76,16 +75,16 @@ def ProbeCreateProcessA(Tag: str, AppName: str, CommandLine: str,
|
||||
string.strcpy(CmdBuffer, CommandLine)
|
||||
|
||||
# si/pi:T() 构造只 alloca 不 memset,必须显式清零
|
||||
# 先例:TransPyV/App/lib/Phase/BuildPipeline.vp:530-532
|
||||
# (string.memset(t.CPtr(c.Addr(si)), 0, STARTUPINFOA.__sizeof__()))
|
||||
# 先例:ViperC/App/lib/Phase/BuildPipeline.vp:530-532
|
||||
# (string.memset(rawptr(c.Addr(si)), 0, STARTUPINFOA.__sizeof__()))
|
||||
# 类型引用写法:includes/subprocess.vp:99-100
|
||||
# c.Addr() 取址:includes/condition.vp:26;t.CPtr(c.Addr(x)):includes/subprocess.vp:121
|
||||
StartupInfo: w32.win32process.STARTUPINFOA = w32.win32process.STARTUPINFOA()
|
||||
ProcessInfo: w32.win32process.PROCESS_INFORMATION = w32.win32process.PROCESS_INFORMATION()
|
||||
string.memset(t.CPtr(&StartupInfo), 0, w32.win32process.STARTUPINFOA.__sizeof__())
|
||||
string.memset(t.CPtr(&ProcessInfo), 0, w32.win32process.PROCESS_INFORMATION.__sizeof__())
|
||||
# c.Addr() 取址:includes/condition.vp:26;rawptr(c.Addr(x)):includes/subprocess.vp:121
|
||||
StartupInfo: win32.win32process.STARTUPINFOA = win32.win32process.STARTUPINFOA()
|
||||
ProcessInfo: win32.win32process.PROCESS_INFORMATION = win32.win32process.PROCESS_INFORMATION()
|
||||
string.memset(rawptr(&StartupInfo), 0, win32.win32process.STARTUPINFOA.__sizeof__())
|
||||
string.memset(rawptr(&ProcessInfo), 0, win32.win32process.PROCESS_INFORMATION.__sizeof__())
|
||||
# si.cb = 结构体大小:includes/subprocess.vp:100
|
||||
StartupInfo.cb = w32.win32process.STARTUPINFOA.__sizeof__()
|
||||
StartupInfo.cb = win32.win32process.STARTUPINFOA.__sizeof__()
|
||||
|
||||
# 应用名描述:None 显式打印成 NULL(不臆造内容,也不兜底成别的路径)
|
||||
AppDesc: str = "NULL"
|
||||
@@ -93,24 +92,24 @@ def ProbeCreateProcessA(Tag: str, AppName: str, CommandLine: str,
|
||||
AppDesc = AppName
|
||||
|
||||
# GetLastError 基线:调用前读取,用于判定 err 是否为残留值
|
||||
# GetLastError 声明:includes/w32/win32base.vp:62
|
||||
# GetLastError 声明:includes/win32/win32base.vp:62
|
||||
# 调用后紧跟读取的先例:ViperApps/ViperZipfileProject/App/main.vp:116
|
||||
PreError: uint32 = w32.win32base.GetLastError()
|
||||
PreError: uint32 = win32.win32base.GetLastError()
|
||||
|
||||
# 单条调用:10 实参,lpEnvironment / lpCurrentDirectory 恒 NULL
|
||||
# 先例:includes/subprocess.vp:112-123(t.CPtr(0) 表 NULL 见 :113/:115/:119/:120)
|
||||
OkValue: int = w32.win32process.CreateProcessA(
|
||||
AppName, CmdBuffer, t.CPtr(0), t.CPtr(0), InheritHandles, CreationFlags,
|
||||
t.CPtr(0), t.CPtr(0), t.CPtr(&StartupInfo), t.CPtr(&ProcessInfo))
|
||||
# 先例:includes/subprocess.vp:112-123(None 表 NULL 见 :113/:115/:119/:120)
|
||||
OkValue: int = win32.win32process.CreateProcessA(
|
||||
AppName, CmdBuffer, None, None, InheritHandles, CreationFlags,
|
||||
None, None, rawptr(&StartupInfo), rawptr(&ProcessInfo))
|
||||
# GetLastError 必须紧跟调用读取(printf 等都会覆盖它)
|
||||
ErrorValue: uint32 = w32.win32base.GetLastError()
|
||||
ErrorValue: uint32 = win32.win32base.GetLastError()
|
||||
|
||||
# --- 字段转储:整数字段与指针字段统一 uint64() 后按 %llu 打印 ---
|
||||
# uint64(结构体字段) 先例:TransPyV/App/lib/Stub/StubMerger/StubMergerStore.vp:79
|
||||
# uint64(结构体字段) 先例:ViperC/App/lib/Stub/StubMerger/StubMergerStore.vp:79
|
||||
# (uint64(scan_result.Entries))
|
||||
# uint64(c.Addr(x)) 先例:ViperApps/ViperOS/VKernel/Kernel/sched/sched.vp:217
|
||||
# (entry_addr: uint64 = uint64(c.Addr(_thread_entry)))
|
||||
# uint64(malloc 缓冲) 先例:TransPyV/App/lib/Stub/StubMerger/StubMergerBuild.vp:1313 段
|
||||
# uint64(malloc 缓冲) 先例:ViperC/App/lib/Stub/StubMerger/StubMergerBuild.vp:1313 段
|
||||
# (uint64(ext_ptr))
|
||||
# %llu 先例:includes/memhub.vp:792
|
||||
CbValue: uint64 = uint64(StartupInfo.cb)
|
||||
@@ -129,7 +128,7 @@ def ProbeCreateProcessA(Tag: str, AppName: str, CommandLine: str,
|
||||
Tag, OkValue, uint64(ErrorValue), uint64(PreError),
|
||||
AppDesc, CommandLine, CmdAddress)
|
||||
# si 关键字段:cb / dwFlags / cbReserved2 / lpReserved2 / 三个 hStd* + si/pi 地址
|
||||
# 字段定义:includes/w32/win32process.vp:42-60(STARTUPINFOA)
|
||||
# 字段定义:includes/win32/win32process.vp:42-60(STARTUPINFOA)
|
||||
stdio.printf("[CPW] %s si.cb=%llu si.dwFlags=%llu si.cbReserved2=%llu si.lpReserved2=%llu si.hStdIn=%llu si.hStdOut=%llu si.hStdErr=%llu si.addr=%llu pi.addr=%llu\n",
|
||||
Tag, CbValue, FlagsValue, CbReserved2Value, Reserved2Value,
|
||||
StdInputValue, StdOutputValue, StdErrorValue, SiAddress, PiAddress)
|
||||
@@ -137,8 +136,8 @@ def ProbeCreateProcessA(Tag: str, AppName: str, CommandLine: str,
|
||||
# 成功时关闭子进程句柄(避免句柄泄漏)
|
||||
# 先例:includes/subprocess.vp:179-180
|
||||
if OkValue != 0:
|
||||
w32.win32base.CloseHandle(ProcessInfo.hThread)
|
||||
w32.win32base.CloseHandle(ProcessInfo.hProcess)
|
||||
win32.win32base.CloseHandle(ProcessInfo.hThread)
|
||||
win32.win32base.CloseHandle(ProcessInfo.hProcess)
|
||||
stdlib.free(CmdBuffer)
|
||||
# stdout 全缓冲,逐组刷新以保证崩溃前输出可见
|
||||
# 先例:ViperApps/ViperZipfileProject/App/main.vp:33(stdio.fflush(None))
|
||||
@@ -152,22 +151,22 @@ def ProbeCreateProcessA(Tag: str, AppName: str, CommandLine: str,
|
||||
def PrintCurrentDirectory() -> int:
|
||||
"""[CPW] 对照组:打印本进程当前目录与错误码"""
|
||||
# 缓冲与调用形态先例:includes/os/_win32.vp:76-91(getcwd:malloc → 调用 →
|
||||
# buf[length] = 0 → str(buf));MAX_PATH 声明:includes/w32/win32base.vp:18
|
||||
# buf[length] = 0 → str(buf));MAX_PATH 声明:includes/win32/win32base.vp:18
|
||||
CwdLength: ULONG = 0
|
||||
CwdError: uint32 = 0
|
||||
CwdDesc: str = "<empty>"
|
||||
CwdBuffer: bytes = stdlib.malloc(w32.win32base.MAX_PATH + 1)
|
||||
CwdBuffer: bytes = stdlib.malloc(win32.win32base.MAX_PATH + 1)
|
||||
if CwdBuffer is None:
|
||||
stdio.printf("[CPW] control GetCurrentDirectoryA MALLOC-FAILED\n")
|
||||
return 1
|
||||
# GetCurrentDirectoryA 声明:includes/w32/win32file.vp:129
|
||||
CwdLength = w32.win32file.GetCurrentDirectoryA(w32.win32base.MAX_PATH + 1, CwdBuffer)
|
||||
CwdError = w32.win32base.GetLastError() # 必须紧跟调用读取
|
||||
# GetCurrentDirectoryA 声明:includes/win32/win32file.vp:129
|
||||
CwdLength = win32.win32file.GetCurrentDirectoryA(win32.win32base.MAX_PATH + 1, CwdBuffer)
|
||||
CwdError = win32.win32base.GetLastError() # 必须紧跟调用读取
|
||||
if CwdLength > 0:
|
||||
if CwdLength < w32.win32base.MAX_PATH + 1:
|
||||
if CwdLength < win32.win32base.MAX_PATH + 1:
|
||||
CwdBuffer[CwdLength] = 0
|
||||
else:
|
||||
CwdBuffer[w32.win32base.MAX_PATH] = 0 # 缓冲区不足:截断显示
|
||||
CwdBuffer[win32.win32base.MAX_PATH] = 0 # 缓冲区不足:截断显示
|
||||
CwdDesc = str(CwdBuffer)
|
||||
stdio.printf("[CPW] control GetCurrentDirectoryA len=%llu err=%llu cwd=%s\n",
|
||||
uint64(CwdLength), uint64(CwdError), CwdDesc)
|
||||
@@ -176,20 +175,15 @@ def PrintCurrentDirectory() -> int:
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# main: 入口
|
||||
# @t.CExport + main() -> int 先例:ViperApps/ViperZipfileProject/App/main.vp:305-306
|
||||
# ============================================================
|
||||
@t.CExport
|
||||
def main() -> int:
|
||||
export def main() -> int:
|
||||
# 控制台 UTF-8(中文注释/标签不乱码)
|
||||
# 声明:includes/w32/win32console.vp:81-82
|
||||
# 声明:includes/win32/win32console.vp:81-82
|
||||
# 先例:ViperApps/ViperQtHelloWorld/App/main.vp:18+34-35
|
||||
w32.win32console.SetConsoleOutputCP(PAGE_CODE)
|
||||
w32.win32console.SetConsoleCP(PAGE_CODE)
|
||||
win32.win32console.SetConsoleOutputCP(PAGE_CODE)
|
||||
win32.win32console.SetConsoleCP(PAGE_CODE)
|
||||
|
||||
# stdio.printf 声明:includes/stdio.vp:4
|
||||
stdio.printf("ViperCPW: CreateProcessA standalone repro (Viper host, not TransPyV.exe)\n")
|
||||
stdio.printf("ViperCPW: CreateProcessA standalone repro (Viper host, not viperc.exe)\n")
|
||||
PrintCurrentDirectory()
|
||||
|
||||
# #1 基线:NULL 应用名 + inh=1 + flags=0
|
||||
@@ -197,14 +191,14 @@ def main() -> int:
|
||||
# #2 同 #1 但 bInheritHandles=0
|
||||
ProbeCreateProcessA("#2 NULL-app inh=0 flags=0", None, "llc --version", 0, 0)
|
||||
# #3 同 #1 但 dwCreationFlags=CREATE_NO_WINDOW
|
||||
# CREATE_NO_WINDOW 定义:includes/w32/win32process.vp:23
|
||||
# CREATE_NO_WINDOW 定义:includes/win32/win32process.vp:23
|
||||
ProbeCreateProcessA("#3 NULL-app inh=1 flags=CREATE_NO_WINDOW", None, "llc --version",
|
||||
1, w32.win32process.CREATE_NO_WINDOW)
|
||||
1, win32.win32process.CREATE_NO_WINDOW)
|
||||
# #4 绝对路径应用名
|
||||
ProbeCreateProcessA("#4 abs-app", "D:\\msys64\\clang64\\bin\\llc.exe", "llc --version", 1, 0)
|
||||
# #5 报错里那条原样命令行(正斜杠相对路径,与 TPV 探针 #3 逐字相同)
|
||||
# #5 报错里那条原样命令行(正斜杠相对路径,与 VPC 探针 #3 逐字相同)
|
||||
ProbeCreateProcessA("#5 raw-cmdline(fwd slashes)", None,
|
||||
"llc -filetype=obj -relocation-model=pic -o ./TransPyV/.tpv_build/output/xx/xxx.obj ./TransPyV/.tpv_build/temp/xx/xxx.ll",
|
||||
"llc -filetype=obj -relocation-model=pic -o ./ViperC/__vpcbuild__/output/xx/xxx.obj ./ViperC/__vpcbuild__/temp/xx/xxx.ll",
|
||||
1, 0)
|
||||
|
||||
stdio.printf("ViperCPW: DONE\n")
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
*.o
|
||||
*.obj
|
||||
*.exe
|
||||
*.img
|
||||
*.iso
|
||||
**/__pycache__/
|
||||
.cache/
|
||||
*.pyc
|
||||
|
||||
# 编译
|
||||
**/output/
|
||||
**/temp/
|
||||
**/__vpcbuild__/
|
||||
@@ -1,158 +0,0 @@
|
||||
# main2.vp — ViperFLProject fltk GUI 测试(回调 + 控件展示)
|
||||
#
|
||||
# 构建需 VPC/TPC 支持 project.vpj linker.static_libs 静态链接
|
||||
# (本工程已配置链接 ../includes/fltk/cfltk/build 下的 cfltk2 + FLTK 静态库)。
|
||||
#
|
||||
# 回调说明:Viper 模块级函数可直接作为 Fl_Callback 传入(VPC 自动把函数名
|
||||
# bitcast 为函数指针)。回调签名统一为 def cb(w: bytes, data: bytes),
|
||||
# 其中 w 是触发回调的控件指针,data 是注册时传入的用户数据。
|
||||
import t, c
|
||||
import stdlib
|
||||
import viperlib
|
||||
import fltk
|
||||
|
||||
|
||||
# 模块级全局:供回调访问 main() 中创建的控件指针(回调是 C 层直接调用,
|
||||
# 拿不到 main 的局部变量);空指针用 None(C null),不能用整数 0。
|
||||
term_ptr: t.CPtr = None
|
||||
status_ptr: t.CPtr = None
|
||||
scheme_idx: int = 0
|
||||
theme_idx: int = 0
|
||||
|
||||
|
||||
def on_btn_click(w: bytes, data: bytes):
|
||||
"""按钮点击回调:改按钮文字 + 状态栏显示"""
|
||||
fltk.Fl_Widget_set_label(w, "Clicked!")
|
||||
fltk.Fl_Widget_redraw(w)
|
||||
fltk.Fl_Output_set_value(status_ptr, "Button clicked")
|
||||
|
||||
|
||||
def on_check(w: bytes, data: bytes):
|
||||
"""复选框回调:状态栏显示勾选状态"""
|
||||
v: int = fltk.Fl_Check_Button_is_checked(w)
|
||||
if v != 0:
|
||||
fltk.Fl_Output_set_value(status_ptr, "Checked")
|
||||
else:
|
||||
fltk.Fl_Output_set_value(status_ptr, "Unchecked")
|
||||
|
||||
|
||||
def on_slider(w: bytes, data: bytes):
|
||||
"""滑动条回调:状态栏实时显示数值"""
|
||||
v: double = fltk.Fl_Slider_value(w)
|
||||
buf: bytes = stdlib.malloc(32)
|
||||
if buf is not None:
|
||||
viperlib.snprintf(buf, 32, "Slider = %.2f", v)
|
||||
fltk.Fl_Output_set_value(status_ptr, buf)
|
||||
stdlib.free(buf)
|
||||
|
||||
|
||||
def on_go(w: bytes, data: bytes):
|
||||
"""按钮回调:读取输入框文本 → 终端打印"""
|
||||
txt: str = fltk.Fl_Input_value(data)
|
||||
fltk.Fl_Terminal_append(term_ptr, "input: ")
|
||||
fltk.Fl_Terminal_append(term_ptr, txt)
|
||||
fltk.Fl_Terminal_append(term_ptr, "\n")
|
||||
|
||||
|
||||
def on_menu_open(w: bytes, data: bytes):
|
||||
fltk.Fl_Output_set_value(status_ptr, "Menu: File/Open")
|
||||
|
||||
|
||||
def on_menu_about(w: bytes, data: bytes):
|
||||
fltk.Fl_Output_set_value(status_ptr, "Menu: Help/About")
|
||||
|
||||
|
||||
def on_style(w: bytes, data: bytes):
|
||||
"""风格切换回调:base→plastic→gtk+→gleam→oxy 循环"""
|
||||
global scheme_idx
|
||||
scheme_idx = scheme_idx + 1
|
||||
if scheme_idx == 1:
|
||||
fltk.Fl.set_scheme("plastic")
|
||||
elif scheme_idx == 2:
|
||||
fltk.Fl.set_scheme("gtk+")
|
||||
elif scheme_idx == 3:
|
||||
fltk.Fl.set_scheme("gleam")
|
||||
elif scheme_idx == 4:
|
||||
fltk.Fl.set_scheme("oxy")
|
||||
else:
|
||||
fltk.Fl.set_scheme("base")
|
||||
scheme_idx = 0
|
||||
fltk.Fl_Output_set_value(status_ptr, f"Scheme: {fltk.Fl.scheme_string()}")
|
||||
|
||||
|
||||
def on_theme(w: bytes, data: bytes):
|
||||
"""Fl_Theme 主题切换:base→Dark→Metro 循环"""
|
||||
global theme_idx
|
||||
theme_idx = theme_idx + 1
|
||||
if theme_idx == 1:
|
||||
fltk.Fl.set_theme_dark()
|
||||
elif theme_idx == 2:
|
||||
fltk.Fl.set_theme_metro()
|
||||
else:
|
||||
fltk.Fl.set_scheme("base")
|
||||
fltk.Fl.reload_scheme()
|
||||
theme_idx = 0
|
||||
fltk.Fl_Output_set_value(status_ptr, f"Theme: {theme_idx}")
|
||||
|
||||
|
||||
def on_tick(w: bytes, data: bytes):
|
||||
"""定时器回调:每秒终端打印一次并续订"""
|
||||
fltk.Fl_Terminal_append(term_ptr, "tick\n")
|
||||
fltk.Fl.add_timeout(1.0, on_tick, 0)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
global term_ptr, status_ptr
|
||||
fltk.Fl_init_all()
|
||||
|
||||
win = fltk.Fl_Window(600, 460, "Viper FLTK Demo")
|
||||
menubar = fltk.Fl_Menu_Bar(0, 0, 600, 25)
|
||||
status = fltk.Fl_Output(10, 30, 580, 25)
|
||||
btn = fltk.Fl_Button(10, 70, 120, 30, "Click Me")
|
||||
check = fltk.Fl_Check_Button(150, 70, 100, 30, "Enable")
|
||||
slider = fltk.Fl_Slider(280, 70, 200, 30)
|
||||
input_ = fltk.Fl_Input(10, 110, 210, 30, "Type here")
|
||||
go = fltk.Fl_Button(230, 110, 55, 30, "Go")
|
||||
style = fltk.Fl_Button(295, 110, 55, 30, "Style")
|
||||
theme = fltk.Fl_Button(360, 110, 55, 30, "Theme")
|
||||
spinner = fltk.Fl_Spinner(425, 110, 100, 30)
|
||||
browser = fltk.Fl_Browser(10, 150, 280, 140)
|
||||
tree = fltk.Fl_Tree(300, 150, 280, 140)
|
||||
term = fltk.Fl_Terminal(10, 300, 570, 120, "Terminal")
|
||||
win.end()
|
||||
|
||||
# 保存全局指针(回调用)
|
||||
term_ptr = t.CPtr(term._ptr)
|
||||
status_ptr = t.CPtr(status._ptr)
|
||||
|
||||
# 菜单(回调 + 快捷键 Ctrl+O:0x4000 | 'o'(111))
|
||||
menubar.add("File/Open", 0x4000 | 111, 0, on_menu_open)
|
||||
menubar.add("Help/About", 0, 0, on_menu_about)
|
||||
|
||||
# 回调注册
|
||||
btn.set_callback(on_btn_click, 0)
|
||||
check.set_callback(on_check, 0)
|
||||
slider.set_callback(on_slider, 0)
|
||||
go.set_callback(on_go, input_._ptr)
|
||||
style.set_callback(on_style, 0)
|
||||
theme.set_callback(on_theme, 0)
|
||||
|
||||
# 数值微调框
|
||||
spinner.set_minimum(0.0)
|
||||
spinner.set_maximum(100.0)
|
||||
spinner.set_step(1.0)
|
||||
spinner.set_value(42.0)
|
||||
|
||||
# 列表 + 树
|
||||
browser.add("Item 1")
|
||||
browser.add("Item 2")
|
||||
browser.add("Item 3")
|
||||
tree.add("Root/Child A/Leaf 1")
|
||||
tree.add("Root/Child B")
|
||||
|
||||
# 定时器
|
||||
fltk.Fl.add_timeout(1.0, on_tick, 0)
|
||||
|
||||
win.show()
|
||||
fltk.Fl.run()
|
||||
return 0
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 TermiNexus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,289 +0,0 @@
|
||||
# Viper Template Project
|
||||
|
||||
[English](#english) | [中文](#中文)
|
||||
|
||||
A minimal, ready-to-use template for bootstrapping a new [Viper](../wiki/01-overview.md) language project on **Windows (x86_64-pc-windows-gnu)**.
|
||||
|
||||
Windows 平台(x86_64-pc-windows-gnu)下 [Viper](../wiki/01-overview.md) 语言新项目的最小可用模板。
|
||||
|
||||
---
|
||||
|
||||
<a id="中文"></a>
|
||||
|
||||
## 中文
|
||||
|
||||
### 这是什么
|
||||
|
||||
`ViperTemplateProject` 是基于 `Viper` 语言的 **Windows 桌面应用模板**。克隆本仓库后,你可以立即得到一个能够:
|
||||
|
||||
- 设置 Windows 控制台为 UTF-8 编码(避免中文乱码)
|
||||
- 打印一行 `你好,世界`
|
||||
- 通过 `llc + clang++`(mingw 工具链)编译为原生 `app.exe`
|
||||
|
||||
的最小 Viper 项目。
|
||||
|
||||
模板对应的语言编译器是 [TransPyC](https://git.gvsds.com/GVSDS/TransPyC);关于 Viper 语言本身的概览,参见 [TransPyC 仓库 wiki](../wiki/01-overview.md)。
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
ViperTemplateProject/
|
||||
├── .gitignore # 忽略 build/、*.o、*.exe、缓存等
|
||||
├── README.md # 本文件
|
||||
├── project.vpj # 项目配置(编译器、链接器、目标三元组等)
|
||||
└── App/
|
||||
└── main.py # 入口文件
|
||||
```
|
||||
|
||||
### 前提条件
|
||||
|
||||
| 工具 | 说明 |
|
||||
|------|------|
|
||||
| `python` ≥ 3.10 | 用于运行 TransPyC 编译器 |
|
||||
| `llc` | LLVM 静态编译器,编译 `.ll` → `.o` |
|
||||
| `clang++` | mingw 工具链下的链接驱动(`x86_64-w64-mingw32`) |
|
||||
| `TransPyC` 仓库 | 本编译器,克隆在 `ViperTemplateProject/..` 同一目录下 |
|
||||
|
||||
环境变量建议(PowerShell):
|
||||
|
||||
```powershell
|
||||
$env:PATH = "D:\msys64\mingw64\bin;D:\LLVM\bin;$env:PATH"
|
||||
```
|
||||
|
||||
### 快速开始
|
||||
|
||||
```powershell
|
||||
# 1. 确保目录布局正确
|
||||
# D:\Users\TermiNexus\Desktop\TransPyC\
|
||||
# ├── TransPyC\ # 编译器仓库
|
||||
# └── ViperTemplateProject\ # 本仓库
|
||||
|
||||
cd D:\Users\TermiNexus\Desktop\TransPyC\ViperTemplateProject
|
||||
|
||||
# 2. 编译并运行
|
||||
python ..\TransPyC\Projectrans.py `
|
||||
--project .\project.vpj `
|
||||
--clean-cache=false
|
||||
|
||||
# 3. 产物位于 output\app.exe
|
||||
.\output\app.exe
|
||||
```
|
||||
|
||||
预期输出:
|
||||
|
||||
```
|
||||
你好,世界
|
||||
```
|
||||
|
||||
### 编写你的第一个程序
|
||||
|
||||
打开 `App/main.py`,替换 `print("你好,世界")` 为任意合法 Viper 表达式。例如:
|
||||
|
||||
```python
|
||||
import w32.win32console as w32cmd
|
||||
import t, c
|
||||
|
||||
pagecode: t.CDefine = 65001
|
||||
|
||||
@t.CExport
|
||||
def main() -> int:
|
||||
w32cmd.SetConsoleOutputCP(pagecode)
|
||||
w32cmd.SetConsoleCP(pagecode)
|
||||
|
||||
# 你的代码从这里开始
|
||||
a: t.CInt = 1
|
||||
b: t.CInt = 2
|
||||
print("a + b =", a + b)
|
||||
|
||||
return 0
|
||||
```
|
||||
|
||||
### 修改项目配置
|
||||
|
||||
打开 `project.vpj`,按需调整:
|
||||
|
||||
| 字段 | 含义 | 模板默认值 |
|
||||
|------|------|-----------|
|
||||
| `name` | 项目名(仅显示用) | `Standard Template Project` |
|
||||
| `source_dir` | 源文件根目录 | `./App` |
|
||||
| `temp_dir` | 中间产物目录(`.pyi` / `.stub.ll`) | `./temp` |
|
||||
| `output_dir` | 最终产物目录 | `./output` |
|
||||
| `compiler.cmd` | 汇编器 | `llc` |
|
||||
| `compiler.flags` | 传给 `llc` 的参数 | `["-filetype=obj", "-relocation-model=pic"]` |
|
||||
| `linker.cmd` | 链接器 | `clang++` |
|
||||
| `linker.flags` | 链接器参数 | mingw 标准库 + `kernel32` |
|
||||
| `linker.output` | 产物名 | `app.exe` |
|
||||
| `includes` | 标准库搜索路径 | `["../includes"]` |
|
||||
| `target.triple` | LLVM 目标三元组 | `x86_64-pc-windows-gnu` |
|
||||
| `target.datalayout` | LLVM 数据布局 | mingw 默认 |
|
||||
| `options.target` | 后端目标 | `llvm` |
|
||||
| `options.strict_mode` | 严格类型检查 | `true` |
|
||||
| `options.slice_level` | 切片级别 | `3` |
|
||||
|
||||
### 跨平台使用
|
||||
|
||||
本模板默认针对 **Windows + mingw**。若需在其他平台使用,修改 `project.vpj` 的 `compiler.cmd` / `linker.cmd` / `target.triple`:
|
||||
|
||||
- **Linux (x86_64)**:`triple = "x86_64-unknown-linux-gnu"`,`linker.cmd = "clang++"`
|
||||
- **macOS (x86_64)**:`triple = "x86_64-apple-darwin*"`,`linker.cmd = "clang++"`
|
||||
- **裸机 x86_64 (ViperOS)**:`triple = "x86_64-none-elf"`,`linker.cmd = "ld.lld"`,需要 `isr.s` 启动文件
|
||||
|
||||
### 常见问题
|
||||
|
||||
**Q: 报错 `cannot find includes/os` / `cannot find includes/atom` 之类?**
|
||||
A: 检查 `project.vpj` 中的 `includes` 字段是否指向 `TransPyC/includes`。`../includes` 假设本仓库与 `TransPyC` 仓库同级。
|
||||
|
||||
**Q: 输出 `app.exe` 双击闪退?**
|
||||
A: 在终端中运行 `.\output\app.exe` 而非双击,并确认 mingw 与 LLVM 在 `PATH` 中。
|
||||
|
||||
**Q: 想完全清理构建产物?**
|
||||
A: 使用 `python ..\TransPyC\Projectrans.py --project .\project.vpj --clean-cache` 清理缓存;删除 `output/` 和 `temp/` 即可彻底重置。
|
||||
|
||||
**Q: `StandardTemplateProject` 和本仓库是什么关系?**
|
||||
A: 本仓库 `ViperTemplateProject` 是 `StandardTemplateProject` 的独立仓库版本。如果你仍想保留 `StandardTemplateProject` 放在 `TransPyC` 仓库内,只需把它加入 `TransPyC/.gitignore` 的 `# 排除独立仓库的目录` 小节。
|
||||
|
||||
### 进一步阅读
|
||||
|
||||
- [Viper 语言概览](../wiki/01-overview.md)
|
||||
- [类型系统](../wiki/02-type-system.md)
|
||||
- [OOP 与对象模型](../wiki/06-oop.md)
|
||||
- [自举路线图](../wiki/13-bootstrapping.md)
|
||||
|
||||
---
|
||||
|
||||
<a id="english"></a>
|
||||
|
||||
## English
|
||||
|
||||
### What is this
|
||||
|
||||
`ViperTemplateProject` is a **Windows desktop application template** based on the [Viper](../wiki/01-overview.md) language. After cloning, you immediately have a minimal Viper project that:
|
||||
|
||||
- Sets the Windows console to UTF-8 (avoids mojibake for non-ASCII output)
|
||||
- Prints `你好,世界`
|
||||
- Compiles to a native `app.exe` via `llc + clang++` (mingw toolchain)
|
||||
|
||||
The corresponding compiler is [TransPyC](https://git.gvsds.com/GVSDS/TransPyC). For a Viper language overview, see the [TransPyC wiki](../wiki/01-overview.md).
|
||||
|
||||
### Directory layout
|
||||
|
||||
```
|
||||
ViperTemplateProject/
|
||||
├── .gitignore # ignores build/, *.o, *.exe, caches, etc.
|
||||
├── README.md # this file
|
||||
├── project.vpj # project config (compiler, linker, target triple, ...)
|
||||
└── App/
|
||||
└── main.py # entry point
|
||||
```
|
||||
|
||||
### Prerequisites
|
||||
|
||||
| Tool | Notes |
|
||||
|------|-------|
|
||||
| `python` ≥ 3.10 | runs the TransPyC compiler |
|
||||
| `llc` | LLVM static compiler, `.ll` → `.o` |
|
||||
| `clang++` | mingw toolchain driver (`x86_64-w64-mingw32`) |
|
||||
| `TransPyC` repo | the compiler, cloned as a sibling of `ViperTemplateProject` |
|
||||
|
||||
Suggested `PATH` (PowerShell):
|
||||
|
||||
```powershell
|
||||
$env:PATH = "D:\msys64\mingw64\bin;D:\LLVM\bin;$env:PATH"
|
||||
```
|
||||
|
||||
### Quick start
|
||||
|
||||
```powershell
|
||||
# 1. Make sure the layout is right
|
||||
# D:\Users\TermiNexus\Desktop\TransPyC\
|
||||
# ├── TransPyC\ # compiler repo
|
||||
# └── ViperTemplateProject\ # this repo
|
||||
|
||||
cd D:\Users\TermiNexus\Desktop\TransPyC\ViperTemplateProject
|
||||
|
||||
# 2. Build and run
|
||||
python ..\TransPyC\Projectrans.py `
|
||||
--project .\project.vpj `
|
||||
--clean-cache=false
|
||||
|
||||
# 3. Output is at output\app.exe
|
||||
.\output\app.exe
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```
|
||||
你好,世界
|
||||
```
|
||||
|
||||
### Writing your first program
|
||||
|
||||
Open `App/main.py` and replace `print("你好,世界")` with any valid Viper expression. Example:
|
||||
|
||||
```python
|
||||
import w32.win32console as w32cmd
|
||||
import t, c
|
||||
|
||||
pagecode: t.CDefine = 65001
|
||||
|
||||
@t.CExport
|
||||
def main() -> int:
|
||||
w32cmd.SetConsoleOutputCP(pagecode)
|
||||
w32cmd.SetConsoleCP(pagecode)
|
||||
|
||||
# your code goes here
|
||||
a: t.CInt = 1
|
||||
b: t.CInt = 2
|
||||
print("a + b =", a + b)
|
||||
|
||||
return 0
|
||||
```
|
||||
|
||||
### Editing project.vpj
|
||||
|
||||
| Field | Meaning | Template default |
|
||||
|-------|---------|------------------|
|
||||
| `name` | display name | `Standard Template Project` |
|
||||
| `source_dir` | source root | `./App` |
|
||||
| `temp_dir` | intermediate artifacts (`.pyi` / `.stub.ll`) | `./temp` |
|
||||
| `output_dir` | final artifacts | `./output` |
|
||||
| `compiler.cmd` | assembler | `llc` |
|
||||
| `compiler.flags` | flags passed to `llc` | `["-filetype=obj", "-relocation-model=pic"]` |
|
||||
| `linker.cmd` | linker | `clang++` |
|
||||
| `linker.flags` | linker flags | mingw stdlib + `kernel32` |
|
||||
| `linker.output` | output name | `app.exe` |
|
||||
| `includes` | standard library search paths | `["../includes"]` |
|
||||
| `target.triple` | LLVM target triple | `x86_64-pc-windows-gnu` |
|
||||
| `target.datalayout` | LLVM data layout | mingw default |
|
||||
| `options.target` | backend target | `llvm` |
|
||||
| `options.strict_mode` | strict type checking | `true` |
|
||||
| `options.slice_level` | slice level | `3` |
|
||||
|
||||
### Cross-platform use
|
||||
|
||||
This template targets **Windows + mingw** by default. To use on another platform, adjust `compiler.cmd` / `linker.cmd` / `target.triple` in `project.vpj`:
|
||||
|
||||
- **Linux (x86_64)**: `triple = "x86_64-unknown-linux-gnu"`, `linker.cmd = "clang++"`
|
||||
- **macOS (x86_64)**: `triple = "x86_64-apple-darwin*"`, `linker.cmd = "clang++"`
|
||||
- **Bare-metal x86_64 (ViperOS)**: `triple = "x86_64-none-elf"`, `linker.cmd = "ld.lld"`, requires `isr.s` startup
|
||||
|
||||
### FAQ
|
||||
|
||||
**Q: Error like `cannot find includes/os` or `cannot find includes/atom`?**
|
||||
A: Check that the `includes` field in `project.vpj` points to the `TransPyC/includes` directory. `../includes` assumes this repo lives next to `TransPyC`.
|
||||
|
||||
**Q: `app.exe` flashes and closes on double-click?**
|
||||
A: Run `.\output\app.exe` from a terminal, not by double-clicking. Make sure mingw and LLVM are on `PATH`.
|
||||
|
||||
**Q: How to fully clean build artifacts?**
|
||||
A: `python ..\TransPyC\Projectrans.py --project .\project.vpj --clean-cache` clears the cache. To reset everything, also delete `output/` and `temp/`.
|
||||
|
||||
**Q: What is the relationship with `StandardTemplateProject`?**
|
||||
A: This repo `ViperTemplateProject` is the standalone-repo version of `StandardTemplateProject`. If you still want `StandardTemplateProject` to live inside the `TransPyC` repo, add it to the `# 排除独立仓库的目录` section in `TransPyC/.gitignore`.
|
||||
|
||||
### Further reading
|
||||
|
||||
- [Viper language overview](../wiki/01-overview.md)
|
||||
- [Type system](../wiki/02-type-system.md)
|
||||
- [OOP and object model](../wiki/06-oop.md)
|
||||
- [Bootstrapping roadmap](../wiki/13-bootstrapping.md)
|
||||
@@ -1,58 +0,0 @@
|
||||
{
|
||||
"name": "ViperFLProject - FLTK GUI Test",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./__vpcbuild__",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": [
|
||||
"-filetype=obj",
|
||||
"-relocation-model=pic"
|
||||
]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++.exe",
|
||||
"flags": [
|
||||
"-fuse-ld=lld",
|
||||
"-lmsvcrt",
|
||||
"-lucrt",
|
||||
"-lpthread",
|
||||
"-lmingwex",
|
||||
"-lkernel32",
|
||||
"-lcomdlg32",
|
||||
"-lcomctl32",
|
||||
"-lole32",
|
||||
"-luuid",
|
||||
"-lwinmm",
|
||||
"-lgdi32",
|
||||
"-lgdiplus",
|
||||
"-ladvapi32",
|
||||
"-lshell32",
|
||||
"-lws2_32",
|
||||
"-luser32",
|
||||
"-lwinspool"
|
||||
],
|
||||
"static_libs": [
|
||||
"../../includes/fltk/cfltk/build/libcfltk2.a",
|
||||
"../../includes/fltk/cfltk/build/libfltk_theme.a",
|
||||
"../../includes/fltk/cfltk/build/fltk/lib/libfltk_images.a",
|
||||
"../../includes/fltk/cfltk/build/fltk/lib/libfltk.a",
|
||||
"../../includes/fltk/cfltk/build/fltk/lib/libfltk_png.a",
|
||||
"../../includes/fltk/cfltk/build/fltk/lib/libfltk_jpeg.a",
|
||||
"../../includes/fltk/cfltk/build/fltk/lib/libfltk_z.a"
|
||||
],
|
||||
"output": "app.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
# 线程模型: 训练在 vthreading 后台线程跑, 只写 MnistNet 的 prog_* 进度总线;
|
||||
# 主线程用 QTimer 轮询刷新界面, 不与之共享 Qt 对象。
|
||||
# ============================================================
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdlib
|
||||
import string
|
||||
@@ -23,8 +22,8 @@ import vthreading
|
||||
import memhub
|
||||
import torch
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import w32.win32file as win32file
|
||||
import win32.fileio as fileio
|
||||
import win32.win32file as win32file
|
||||
import lib.MnistData as MnistData
|
||||
import lib.MnistNet as MnistNet
|
||||
|
||||
@@ -39,8 +38,7 @@ define CHART_KEEP = 800
|
||||
define ANIM_SPAN = 16
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class AppGui:
|
||||
novirtual class AppGui:
|
||||
# ---- 应用与主窗 ----
|
||||
App: vqt6.QApplication*
|
||||
Win: vqt6.QMainWindow*
|
||||
@@ -78,12 +76,12 @@ class AppGui:
|
||||
Pbar: vqt6.QProgressBar*
|
||||
Log: vqt6.QPlainTextEdit*
|
||||
Chart: vqt6.ChartView*
|
||||
LineLoss: t.CPtr
|
||||
LineAcc: t.CPtr
|
||||
LineLoss: rawptr
|
||||
LineAcc: rawptr
|
||||
ChartSynced: int
|
||||
# 验证集曲线(每 epoch 一个点, 与训练曲线分开同步)
|
||||
LineValLoss: t.CPtr
|
||||
LineValAcc: t.CPtr
|
||||
LineValLoss: rawptr
|
||||
LineValAcc: rawptr
|
||||
ChartSyncedVal: int
|
||||
|
||||
# ---- 推理页 ----
|
||||
@@ -122,7 +120,7 @@ class AppGui:
|
||||
# 只存线程句柄: Thread 对象本身是创建帧的栈 alloca, 跨帧持有会悬垂;
|
||||
# 句柄由 on_start_train 在 Thread 尚存活时取出, 之后用模块级
|
||||
# wait_handle/close_handle 操作。
|
||||
ThreadH: t.CPtr
|
||||
ThreadH: rawptr
|
||||
XBuf: double*
|
||||
YBuf: int*
|
||||
NTrain: sizet
|
||||
@@ -138,8 +136,8 @@ class AppGui:
|
||||
Img28: bytes
|
||||
Sample28: bytes
|
||||
HaveSample: int
|
||||
TestRaw: t.CPtr
|
||||
TestLbl: t.CPtr
|
||||
TestRaw: rawptr
|
||||
TestLbl: rawptr
|
||||
TestN: sizet
|
||||
Probs: double*
|
||||
HiddenBuf: double*
|
||||
@@ -337,9 +335,9 @@ class AppGui:
|
||||
self.LblStatus = self.make_label("池: 512MB 数据目录: data", "color:#8a93a1;")
|
||||
# statusBar() 返回裸指针: 返回包装类对象(按值 struct)的方法在跨模块
|
||||
# 调用时返回类型无法精确解析(编译器 fail-fast), 故此处直连 FFI。
|
||||
# 注解写 t.CPtr 而非 vqt6.QtStatusBarPtr —— 跨模块 typedef 注解
|
||||
# 注解写 rawptr 而非 vqt6.QtStatusBarPtr —— 跨模块 typedef 注解
|
||||
# 不在解析白名单内, 会走"类型注解解析失败"诊断路径。
|
||||
sb: t.CPtr = self.Win.statusBar()
|
||||
sb: rawptr = self.Win.statusBar()
|
||||
vqt6.vqt6_qstatusbar_add_widget(sb, self.LblStatus._ptr, 0)
|
||||
|
||||
self.TimerPoll = vqt6.QTimer()
|
||||
@@ -561,8 +559,8 @@ class AppGui:
|
||||
buf: bytes = stdlib.malloc(1024)
|
||||
if buf is None:
|
||||
return "."
|
||||
# hModule 传空指针用 t.CPtr(0): HANDLE 是 VOIDPTR, 整数 0 不能隐式转指针
|
||||
win32file.GetModuleFileNameA(t.CPtr(0), buf, ULONG(1024))
|
||||
# hModule 传空指针用 None: HANDLE 是 VOIDPTR, 整数 0 不能隐式转指针
|
||||
win32file.GetModuleFileNameA(None, buf, ULONG(1024))
|
||||
n: sizet = string.strlen(buf)
|
||||
# 第一步: 从右往左找最后一个路径分隔符, 在那里截断(去掉文件名本身)
|
||||
cut: sizet = 0
|
||||
@@ -862,7 +860,7 @@ class AppGui:
|
||||
self.BtnTrain.setEnabled(0)
|
||||
self.BtnStop.setEnabled(1)
|
||||
self.Training = 1
|
||||
th: vthreading.Thread* = vthreading.Thread(WorkerTrain, t.CPtr(0))
|
||||
th: vthreading.Thread* = vthreading.Thread(WorkerTrain, None)
|
||||
th.start()
|
||||
self.ThreadH = th.handle # 帧内取出句柄, 之后不再持 Thread 对象
|
||||
self.TimerPoll.start(120)
|
||||
@@ -1024,7 +1022,7 @@ class AppGui:
|
||||
return
|
||||
idx: sizet = MnistNet.rand_idx(self.TestN)
|
||||
lb: uchar* = self.TestLbl
|
||||
src: t.CPtr = self.TestRaw + 16 + idx * MnistData.N_IN
|
||||
src: rawptr = self.TestRaw + 16 + idx * MnistData.N_IN
|
||||
string.memcpy(self.Sample28, src, MnistData.N_IN)
|
||||
self.HaveSample = 1
|
||||
self.Canvas.setImage28(self.Sample28)
|
||||
@@ -1144,87 +1142,87 @@ class AppGui:
|
||||
_g_ui: AppGui*
|
||||
|
||||
|
||||
def CbDownload(slot_id: int, data: t.CPtr):
|
||||
def CbDownload(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_download()
|
||||
|
||||
|
||||
def CbCopyLink(slot_id: int, data: t.CPtr):
|
||||
def CbCopyLink(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_copy_link()
|
||||
|
||||
|
||||
def CbPickDir(slot_id: int, data: t.CPtr):
|
||||
def CbPickDir(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_pick_dir()
|
||||
|
||||
|
||||
def CbCheckData(slot_id: int, data: t.CPtr):
|
||||
def CbCheckData(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.check_data()
|
||||
|
||||
|
||||
def CbPickLocal(slot_id: int, data: t.CPtr):
|
||||
def CbPickLocal(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_pick_local()
|
||||
|
||||
|
||||
def CbArchChanged(slot_id: int, data: t.CPtr):
|
||||
def CbArchChanged(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_arch_changed()
|
||||
|
||||
|
||||
def CbStartTrain(slot_id: int, data: t.CPtr):
|
||||
def CbStartTrain(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_start_train()
|
||||
|
||||
|
||||
def CbStopTrain(slot_id: int, data: t.CPtr):
|
||||
def CbStopTrain(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_stop_train()
|
||||
|
||||
|
||||
def CbZoomChart(slot_id: int, data: t.CPtr):
|
||||
def CbZoomChart(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_zoom_chart()
|
||||
|
||||
|
||||
def CbPollTraining(slot_id: int, data: t.CPtr):
|
||||
def CbPollTraining(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_poll_training()
|
||||
|
||||
|
||||
def CbLoadModel(slot_id: int, data: t.CPtr):
|
||||
def CbLoadModel(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_load_model()
|
||||
|
||||
|
||||
def CbPickSample(slot_id: int, data: t.CPtr):
|
||||
def CbPickSample(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_pick_sample()
|
||||
|
||||
|
||||
def CbClearCanvas(slot_id: int, data: t.CPtr):
|
||||
def CbClearCanvas(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_clear_canvas()
|
||||
|
||||
|
||||
def CbCanvasChanged(slot_id: int, data: t.CPtr):
|
||||
def CbCanvasChanged(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_canvas_changed()
|
||||
|
||||
|
||||
def CbUse(slot_id: int, data: t.CPtr):
|
||||
def CbUse(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_use()
|
||||
|
||||
|
||||
def CbAnimTick(slot_id: int, data: t.CPtr):
|
||||
def CbAnimTick(slot_id: int, data: rawptr):
|
||||
if _g_ui is not None:
|
||||
_g_ui.on_anim_tick()
|
||||
|
||||
|
||||
def WorkerTrain(arg: t.CPtr) -> t.CPtr:
|
||||
def WorkerTrain(arg: rawptr) -> rawptr:
|
||||
"""后台训练线程入口"""
|
||||
if _g_ui is not None:
|
||||
_g_ui.worker_train()
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
# 说明: fileio.File.read_all 契约是"最多读 max_count-1 字节并补 NUL",
|
||||
# 故所有整读调用都按 目标长度+1 申请与请求, 否则会丢最后一字节。
|
||||
# ============================================================
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdlib
|
||||
import string
|
||||
import stdio
|
||||
import viperlib
|
||||
import os
|
||||
import w32.fileio as fileio
|
||||
import win32.fileio as fileio
|
||||
import gzip
|
||||
import requests
|
||||
import requests.https as reqhttps
|
||||
@@ -34,20 +33,20 @@ MNIST_BASE: str = "https://ossci-datasets.s3.amazonaws.com/mnist"
|
||||
# ============================================================
|
||||
# 基础读写
|
||||
# ============================================================
|
||||
def be32(buf: t.CPtr, off: sizet) -> uint32:
|
||||
def be32(buf: rawptr, off: sizet) -> uint32:
|
||||
"""IDX 大端 u32"""
|
||||
ub: uchar* = buf
|
||||
return (uint32(ub[off]) << 24) | (uint32(ub[off + 1]) << 16) \
|
||||
| (uint32(ub[off + 2]) << 8) | uint32(ub[off + 3])
|
||||
|
||||
|
||||
def read_file_all(path: str, fsize: sizet) -> t.CPtr:
|
||||
def read_file_all(path: str, fsize: sizet) -> rawptr:
|
||||
"""整读文件到 malloc 缓冲, 失败返回 None
|
||||
注意: read_all 最多读 max_count-1 字节并补 NUL, 故按 fsize+1 申请/请求"""
|
||||
f: fileio.File* = fileio.File(path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
return None
|
||||
buf: t.CPtr = stdlib.malloc(fsize + 1)
|
||||
buf: rawptr = stdlib.malloc(fsize + 1)
|
||||
if buf is None:
|
||||
f.close()
|
||||
return None
|
||||
@@ -102,7 +101,7 @@ def idx_usable(path: str, is_lb: int) -> int:
|
||||
if sz < 16:
|
||||
f.close()
|
||||
return 0
|
||||
hdr: t.CPtr = stdlib.malloc(64)
|
||||
hdr: rawptr = stdlib.malloc(64)
|
||||
if hdr is None:
|
||||
f.close()
|
||||
return 0
|
||||
@@ -161,7 +160,7 @@ def download_inflate(url: str, out_path: str) -> int:
|
||||
if cap < 1024:
|
||||
cap = 1024
|
||||
# 保险起见: ISIZE 与实际不符时报"目标缓冲不足", 就翻倍重试(正常情况下一次成功)
|
||||
dst: t.CPtr = None
|
||||
dst: rawptr = None
|
||||
n: LONG = 0
|
||||
while True:
|
||||
dst = stdlib.malloc(cap)
|
||||
@@ -378,7 +377,7 @@ def load_mnist_images(path: str, dst: double*,
|
||||
f.close()
|
||||
return 0
|
||||
f.close()
|
||||
whole: t.CPtr = read_file_all(path, sizet(sz))
|
||||
whole: rawptr = read_file_all(path, sizet(sz))
|
||||
if whole is None:
|
||||
stdio.printf("[mnist] 读取失败: %s\n", path)
|
||||
return 0
|
||||
@@ -426,7 +425,7 @@ def load_mnist_labels(path: str, dst: int*,
|
||||
f.close()
|
||||
return 0
|
||||
f.close()
|
||||
whole: t.CPtr = read_file_all(path, sizet(sz))
|
||||
whole: rawptr = read_file_all(path, sizet(sz))
|
||||
if whole is None:
|
||||
return 0
|
||||
# IDX 标签魔数: 00 00 08 01
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
# 进度总线: train_run 每个记录点写入 prog_* 数组, UI 线程只读轮询;
|
||||
# prog_stop 置 1 可请求提前结束(训练线程在下一个 step 边界退出)。
|
||||
# ============================================================
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdlib
|
||||
import string
|
||||
@@ -20,7 +19,7 @@ import stdio
|
||||
import math
|
||||
import memhub
|
||||
import torch
|
||||
import w32.fileio as fileio
|
||||
import win32.fileio as fileio
|
||||
# 输入/输出维度与数据层保持单一定义, 避免两处各写一份导致漂移
|
||||
from lib.MnistData import N_IN, N_OUT
|
||||
|
||||
@@ -80,16 +79,15 @@ define GRAPH_IN_SIDE = 8
|
||||
define NET_BYTES = 480
|
||||
|
||||
|
||||
def _zeros_raw(pool: memhub.MemBuddy*, nb: sizet) -> t.CPtr:
|
||||
def _zeros_raw(pool: memhub.MemBuddy*, nb: sizet) -> rawptr:
|
||||
"""从内存池分配并清零一块裸缓冲(动量缓冲用; pool.alloc 不保证清零)"""
|
||||
p: t.CPtr = pool.alloc(nb)
|
||||
p: rawptr = pool.alloc(nb)
|
||||
if p is not None:
|
||||
string.memset(p, 0, nb)
|
||||
return p
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class Net:
|
||||
novirtual class Net:
|
||||
# --- 通用 (1-4) ---
|
||||
Arch: sizet # 1 ARCH_MLP / ARCH_CNN
|
||||
Hidden: sizet # 2 MLP 隐藏层宽度; CNN 的 FC1 宽度
|
||||
@@ -110,28 +108,28 @@ class Net:
|
||||
wf2: torch.Tensor* # 15
|
||||
bf2: torch.Tensor* # 16
|
||||
# --- CNN 前向激活 (17-26) ---
|
||||
BZ1: t.CPtr # 17 conv1 输出 c1*28*28
|
||||
BA1: t.CPtr # 18 relu(BZ1)
|
||||
BP1: t.CPtr # 19 pool1 输出 c1*14*14
|
||||
BZ2: t.CPtr # 20 conv2 输出 c2*14*14
|
||||
BA2: t.CPtr # 21 relu(BZ2)
|
||||
BP2: t.CPtr # 22 pool2 输出 c2*7*7(FC1 的输入)
|
||||
BZ3: t.CPtr # 23 fc1 输出 h
|
||||
BA3: t.CPtr # 24 relu(BZ3)
|
||||
BLG: t.CPtr # 25 logits 10
|
||||
BDA3: t.CPtr # 26 fc1 输出的梯度 h
|
||||
BZ1: rawptr # 17 conv1 输出 c1*28*28
|
||||
BA1: rawptr # 18 relu(BZ1)
|
||||
BP1: rawptr # 19 pool1 输出 c1*14*14
|
||||
BZ2: rawptr # 20 conv2 输出 c2*14*14
|
||||
BA2: rawptr # 21 relu(BZ2)
|
||||
BP2: rawptr # 22 pool2 输出 c2*7*7(FC1 的输入)
|
||||
BZ3: rawptr # 23 fc1 输出 h
|
||||
BA3: rawptr # 24 relu(BZ3)
|
||||
BLG: rawptr # 25 logits 10
|
||||
BDA3: rawptr # 26 fc1 输出的梯度 h
|
||||
# --- CNN 反向梯度 (27-34) ---
|
||||
BDLG: t.CPtr # 27 dlogits 10
|
||||
BGZ3: t.CPtr # 28 fc1 反传的预激活梯度 h
|
||||
BGP2: t.CPtr # 29 fc1 反传的输入梯度 49*c2
|
||||
BGA2: t.CPtr # 30 relu2 的输入梯度 c2*14*14
|
||||
BGZ2: t.CPtr # 31 pool2 反传结果 c2*14*14
|
||||
BGP1: t.CPtr # 32 conv2 反传的输入梯度 c1*14*14
|
||||
BGA1: t.CPtr # 33 relu1 的输入梯度 c1*28*28
|
||||
BGZ1: t.CPtr # 34 pool1 反传结果 c1*28*28
|
||||
BDLG: rawptr # 27 dlogits 10
|
||||
BGZ3: rawptr # 28 fc1 反传的预激活梯度 h
|
||||
BGP2: rawptr # 29 fc1 反传的输入梯度 49*c2
|
||||
BGA2: rawptr # 30 relu2 的输入梯度 c2*14*14
|
||||
BGZ2: rawptr # 31 pool2 反传结果 c2*14*14
|
||||
BGP1: rawptr # 32 conv2 反传的输入梯度 c1*14*14
|
||||
BGA1: rawptr # 33 relu1 的输入梯度 c1*28*28
|
||||
BGZ1: rawptr # 34 pool1 反传结果 c1*28*28
|
||||
# --- CNN 池化 argmax (35-36) ---
|
||||
ARG1: t.CPtr # 35 pool1 窗口内下标(int) c1*14*14
|
||||
ARG2: t.CPtr # 36 pool2 窗口内下标(int) c2*7*7
|
||||
ARG1: rawptr # 35 pool1 窗口内下标(int) c1*14*14
|
||||
ARG2: rawptr # 36 pool2 窗口内下标(int) c2*7*7
|
||||
# --- FC 层 2D 视图壳 (37-44, 每步复用不再分配) ---
|
||||
VF: torch.Tensor* # 37 (1, 49*c2) 复用 BP2
|
||||
VZ3: torch.Tensor* # 38 (1, h) 复用 BZ3
|
||||
@@ -148,27 +146,27 @@ class Net:
|
||||
GBF2: torch.Tensor* # 48
|
||||
# --- MLP 动量缓冲 (49-52) ---
|
||||
# 重球法的速度项, 与参数同元素个数, 训练开始前清零; 只训练时用
|
||||
Mw1: t.CPtr # 49
|
||||
Mb1: t.CPtr # 50
|
||||
Mw2: t.CPtr # 51
|
||||
Mb2: t.CPtr # 52
|
||||
Mw1: rawptr # 49
|
||||
Mb1: rawptr # 50
|
||||
Mw2: rawptr # 51
|
||||
Mb2: rawptr # 52
|
||||
# --- CNN 动量缓冲 (53-60) ---
|
||||
Mwc1: t.CPtr # 53
|
||||
Mbc1: t.CPtr # 54
|
||||
Mwc2: t.CPtr # 55
|
||||
Mbc2: t.CPtr # 56
|
||||
Mwf1: t.CPtr # 57
|
||||
Mbf1: t.CPtr # 58
|
||||
Mwf2: t.CPtr # 59
|
||||
Mbf2: t.CPtr # 60
|
||||
Mwc1: rawptr # 53
|
||||
Mbc1: rawptr # 54
|
||||
Mwc2: rawptr # 55
|
||||
Mbc2: rawptr # 56
|
||||
Mwf1: rawptr # 57
|
||||
Mbf1: rawptr # 58
|
||||
Mwf2: rawptr # 59
|
||||
Mbf2: rawptr # 60
|
||||
|
||||
def __new__(self, pool: memhub.MemBuddy*, hidden: sizet,
|
||||
arch: sizet = ARCH_MLP, c1: sizet = 0,
|
||||
c2: sizet = 0) -> t.CPtr:
|
||||
c2: sizet = 0) -> rawptr:
|
||||
# 网络对象要跨帧存活(Qt 面板里存在 AppGui.Net 字段上, 训练线程还要读),
|
||||
# 而类实例默认是创建函数的栈 alloca —— 必须堆分配。
|
||||
# 整体清零: 未用到的架构字段保持 NULL, 由 ok()/前向按 arch 判断。
|
||||
p: t.CPtr = pool.alloc(NET_BYTES)
|
||||
p: rawptr = pool.alloc(NET_BYTES)
|
||||
if p is not None:
|
||||
string.memset(p, 0, NET_BYTES)
|
||||
return p
|
||||
@@ -413,7 +411,7 @@ def batch_accuracy(logits: torch.Tensor*,
|
||||
# 反向顺序: logits -> fc2 -> relu3 -> fc1 -> pool2 -> relu2 -> conv2
|
||||
# -> pool1 -> relu1 -> conv1
|
||||
# ============================================================
|
||||
def relu_raw(x: t.CPtr, out: t.CPtr, n: sizet):
|
||||
def relu_raw(x: rawptr, out: rawptr, n: sizet):
|
||||
"""out = max(0, x) 逐元素(裸缓冲版, 免去给 4D 缓冲造 2D 视图壳)"""
|
||||
if x is None or out is None:
|
||||
return
|
||||
@@ -427,7 +425,7 @@ def relu_raw(x: t.CPtr, out: t.CPtr, n: sizet):
|
||||
od[i] = double(0.0)
|
||||
|
||||
|
||||
def relu_raw_bwd(za: t.CPtr, g: t.CPtr, gz: t.CPtr, n: sizet):
|
||||
def relu_raw_bwd(za: rawptr, g: rawptr, gz: rawptr, n: sizet):
|
||||
"""gz = g * (za > 0) —— za 是 relu 的输入(预激活)缓冲"""
|
||||
if za is None or g is None or gz is None:
|
||||
return
|
||||
@@ -441,7 +439,7 @@ def relu_raw_bwd(za: t.CPtr, g: t.CPtr, gz: t.CPtr, n: sizet):
|
||||
od[i] = double(0.0)
|
||||
|
||||
|
||||
def cnn_forward(net: Net*, img: t.CPtr):
|
||||
def cnn_forward(net: Net*, img: rawptr):
|
||||
"""img: 784 个 0..1 归一化灰度(double 缓冲); logits 落在 net.BLG"""
|
||||
if net is None or img is None:
|
||||
return
|
||||
@@ -485,7 +483,7 @@ def cnn_zero_grads(net: Net*):
|
||||
torch.zero_grad(net.bf2)
|
||||
|
||||
|
||||
def cnn_backward(net: Net*, img: t.CPtr, label: int) -> double:
|
||||
def cnn_backward(net: Net*, img: rawptr, label: int) -> double:
|
||||
"""反向累积一个样本的参数梯度, 返回该样本交叉熵损失
|
||||
img 必须与 cnn_forward 传入的是同一块缓冲(conv1 反向要用它)"""
|
||||
if net is None:
|
||||
@@ -500,7 +498,7 @@ def cnn_backward(net: Net*, img: t.CPtr, label: int) -> double:
|
||||
s1: sizet = sizet(CNN_SIDE1)
|
||||
n1: sizet = c1 * s * s
|
||||
n2: sizet = c2 * s1 * s1
|
||||
loss_buf: t.CPtr = stdlib.malloc(8)
|
||||
loss_buf: rawptr = stdlib.malloc(8)
|
||||
lab: int* = stdlib.malloc(4)
|
||||
if loss_buf is None or lab is None:
|
||||
if loss_buf is not None:
|
||||
@@ -576,7 +574,7 @@ def _write_tensor(f: fileio.File*, x: torch.Tensor*) -> sizet:
|
||||
return nb
|
||||
|
||||
|
||||
def _read_tensor(whole: t.CPtr, off: sizet,
|
||||
def _read_tensor(whole: rawptr, off: sizet,
|
||||
x: torch.Tensor*) -> sizet:
|
||||
"""从整块缓冲的 off 处读一个张量, 返回新偏移(0 表示失败)"""
|
||||
nb: sizet = _bytes_of(x)
|
||||
@@ -656,7 +654,7 @@ def load_model_mk1(path: str, w1: torch.Tensor*,
|
||||
stdio.printf("[model] 文件过小: %s\n", path)
|
||||
return 1
|
||||
# read_all 契约: 最多读 max_count-1 字节, 故 +1
|
||||
whole: t.CPtr = stdlib.malloc(sizet(sz) + 1)
|
||||
whole: rawptr = stdlib.malloc(sizet(sz) + 1)
|
||||
if whole is None:
|
||||
return 1
|
||||
fr: fileio.File* = fileio.File(path, fileio.MODE.R)
|
||||
@@ -756,7 +754,7 @@ def load_model_mk2(path: str, net: Net*) -> int:
|
||||
stdio.printf("[model] 尺寸不匹配(期望字节=%zu, 实得=%zu)\n",
|
||||
expect, sizet(sz))
|
||||
return 1
|
||||
whole: t.CPtr = stdlib.malloc(sizet(sz) + 1)
|
||||
whole: rawptr = stdlib.malloc(sizet(sz) + 1)
|
||||
if whole is None:
|
||||
return 1
|
||||
fr: fileio.File* = fileio.File(path, fileio.MODE.R)
|
||||
@@ -994,11 +992,11 @@ def ce_from_logits(lg: double*, off: sizet, c: sizet,
|
||||
mx = d[off + j]
|
||||
s: double = double(0.0)
|
||||
for j in range(c):
|
||||
s = s + vipermath.exp(d[off + j] - mx)
|
||||
s = s + math.exp(d[off + j] - mx)
|
||||
li: sizet = sizet(label)
|
||||
if li >= c:
|
||||
li = 0
|
||||
return -(d[off + li] - mx - vipermath.log(s))
|
||||
return -(d[off + li] - mx - math.log(s))
|
||||
|
||||
|
||||
def epoch_lr(lr: double, epoch: sizet, epochs: sizet) -> double:
|
||||
@@ -1307,7 +1305,7 @@ def _train_cnn(pool: memhub.MemBuddy*,
|
||||
# 单样本输入缓冲: MnistData.load_mnist_images 已把像素归一化到 0..1,
|
||||
# 这里只做搬运(可选平移增强), 不再二次除以 255 —— conv 只吃 double,
|
||||
# 且反向 conv1 要用与 forward 同一块缓冲。
|
||||
in_buf: t.CPtr = stdlib.malloc(N_IN * 8)
|
||||
in_buf: rawptr = stdlib.malloc(N_IN * 8)
|
||||
if in_buf is None:
|
||||
prog_fail = 1
|
||||
prog_done = 1
|
||||
@@ -1513,11 +1511,11 @@ def predict_full(w1: torch.Tensor*, b1: torch.Tensor*,
|
||||
mx = lgl[ci]
|
||||
s: double = double(0.0)
|
||||
for ci in range(N_OUT):
|
||||
s = s + vipermath.exp(lgl[ci] - mx)
|
||||
s = s + math.exp(lgl[ci] - mx)
|
||||
best: int = 0
|
||||
bv: double = double(-1.0)
|
||||
for ci in range(N_OUT):
|
||||
p: double = vipermath.exp(lgl[ci] - mx) / s
|
||||
p: double = math.exp(lgl[ci] - mx) / s
|
||||
if out_probs is not None:
|
||||
op: double* = out_probs
|
||||
op[ci] = p
|
||||
@@ -1541,7 +1539,7 @@ def predict_cnn(net: Net*, img28: bytes,
|
||||
if net is None or img28 is None:
|
||||
return -1
|
||||
h: sizet = net.Hidden
|
||||
xbuf: t.CPtr = stdlib.malloc(N_IN * 8)
|
||||
xbuf: rawptr = stdlib.malloc(N_IN * 8)
|
||||
if xbuf is None:
|
||||
return -1
|
||||
x: double* = xbuf
|
||||
@@ -1558,13 +1556,13 @@ def predict_cnn(net: Net*, img28: bytes,
|
||||
mx = ld[ci]
|
||||
s: double = double(0.0)
|
||||
for ci in range(N_OUT):
|
||||
s = s + vipermath.exp(ld[ci] - mx)
|
||||
s = s + math.exp(ld[ci] - mx)
|
||||
if s <= double(0.0):
|
||||
return -1
|
||||
best: int = 0
|
||||
bv: double = double(-1.0)
|
||||
for ci in range(N_OUT):
|
||||
p: double = vipermath.exp(ld[ci] - mx) / s
|
||||
p: double = math.exp(ld[ci] - mx) / s
|
||||
if out_probs is not None:
|
||||
op: double* = out_probs
|
||||
op[ci] = p
|
||||
@@ -1600,7 +1598,7 @@ def evaluate_cnn(net: Net*,
|
||||
return double(0.0)
|
||||
xd: double* = xbuf
|
||||
yd: int* = ybuf
|
||||
in_buf: t.CPtr = stdlib.malloc(N_IN * 8)
|
||||
in_buf: rawptr = stdlib.malloc(N_IN * 8)
|
||||
if in_buf is None:
|
||||
return double(0.0)
|
||||
ind: double* = in_buf
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
# 权重形状同 PyTorch: Conv(out,in,k,k) / Linear(out,in), b(out)
|
||||
# 计算: torch-lite 线性前向走 vipersimd.simd_dot4d, relu 走 simd_max4d
|
||||
# ============================================================
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdlib
|
||||
import string
|
||||
@@ -31,7 +30,7 @@ import memhub
|
||||
import argparse
|
||||
import requests
|
||||
import torch
|
||||
import w32.win32console as w32cmd
|
||||
import win32.win32console as win32cmd
|
||||
import lib.MnistData as MnistData
|
||||
import lib.MnistNet as MnistNet
|
||||
import lib.AppGui as AppGui
|
||||
@@ -270,8 +269,8 @@ def run_cli(pool: memhub.MemBuddy*) -> int:
|
||||
# ============================================================
|
||||
def main() -> int:
|
||||
# UTF-8 控制台(与 ViperC main 一致)
|
||||
w32cmd.SetConsoleOutputCP(CODE_PAGE)
|
||||
w32cmd.SetConsoleCP(CODE_PAGE)
|
||||
win32cmd.SetConsoleOutputCP(CODE_PAGE)
|
||||
win32cmd.SetConsoleCP(CODE_PAGE)
|
||||
|
||||
# 主内存池: CLI 与 GUI 共用, 先建池再解析 argv(GUI 分支也需要池)
|
||||
arena: bytes = stdlib.malloc(POOL_SIZE)
|
||||
|
||||
@@ -6,12 +6,10 @@
|
||||
#
|
||||
# 链接目标尚未定(msys2 预装 3.6.2 动态库 或 openssl_358_C 自编译),
|
||||
# 配好 project.vpj 的 -lcrypto/-lssl(或 static_libs)后才可链接运行。
|
||||
import t, c
|
||||
import stdlib
|
||||
import binascii
|
||||
import openssl
|
||||
import w32.win32console as w32cmd
|
||||
import viperlib
|
||||
import win32.win32console as win32cmd
|
||||
|
||||
|
||||
def print_digest(name: str, buf: bytes, length: int):
|
||||
@@ -20,8 +18,8 @@ def print_digest(name: str, buf: bytes, length: int):
|
||||
|
||||
|
||||
def main() -> int:
|
||||
w32cmd.SetConsoleOutputCP(65001)
|
||||
w32cmd.SetConsoleCP(65001)
|
||||
win32cmd.SetConsoleOutputCP(65001)
|
||||
win32cmd.SetConsoleCP(65001)
|
||||
|
||||
# ---- 1) 版本 ----
|
||||
ver: str = openssl.OpenSSL_version(openssl.OpenSslVersion)
|
||||
@@ -31,7 +29,7 @@ def main() -> int:
|
||||
|
||||
# ---- 2) 摘要 ----
|
||||
data: str = "hello openssl"
|
||||
dlen: int = len(data)
|
||||
dlen: int = int(len(data))
|
||||
|
||||
md5_buf: bytes = stdlib.malloc(openssl.Md5DigestLength)
|
||||
openssl.MD5(data, dlen, md5_buf)
|
||||
|
||||
@@ -15,7 +15,7 @@ import c
|
||||
import vqt6
|
||||
import stdlib
|
||||
import memhub
|
||||
import w32.win32console as w32cmd
|
||||
import win32.win32console as win32cmd
|
||||
import viperlib
|
||||
|
||||
define pagecode = 65001
|
||||
@@ -31,8 +31,8 @@ define POOL_SIZE = 1 * 1024 * 1024
|
||||
def main() -> int:
|
||||
global _mbuddy
|
||||
|
||||
w32cmd.SetConsoleOutputCP(pagecode)
|
||||
w32cmd.SetConsoleCP(pagecode)
|
||||
win32cmd.SetConsoleOutputCP(pagecode)
|
||||
win32cmd.SetConsoleCP(pagecode)
|
||||
|
||||
# 模块内存池 (QApplication([]) 里的 [] 要在这里分配)
|
||||
arena: bytes = stdlib.malloc(POOL_SIZE)
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
# 4) rhttps.post - HTTPS POST
|
||||
#
|
||||
# Usage: requests._mbuddy = my_mbuddy (https reuses the same memory pool)
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import stdlib
|
||||
@@ -18,8 +17,8 @@ import requests
|
||||
import requests.https as rhttps
|
||||
import requests.download as rd
|
||||
import zlib.pyzlib as pyzlib
|
||||
import w32.win32file as wf
|
||||
import w32.win32base as wb
|
||||
import win32.win32file as wf
|
||||
import win32.win32base as wb
|
||||
|
||||
|
||||
# Global MBuddy pointer
|
||||
@@ -298,4 +297,4 @@ def main() -> int:
|
||||
socket.SocketCleanup()
|
||||
stdio.printf("\nViperRequestsTest: DONE\n")
|
||||
return 0
|
||||
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
import w32.win32console as w32cmd
|
||||
import stdio
|
||||
import t, c
|
||||
from stdint import *
|
||||
from t import CInt as MyInt
|
||||
from stdint import BYTE as MyByte
|
||||
import main2
|
||||
|
||||
pagecode: t.CDefine = 65001
|
||||
|
||||
# 类型系统收敛测试:typedef 值引用 from-import 别名(阶段1a 别名链)
|
||||
MyWord: t.CTypedef = MyInt
|
||||
MyDword: t.CTypedef = DWORD
|
||||
|
||||
|
||||
class TestStruct():
|
||||
a: t.CInt
|
||||
b: t.CInt
|
||||
|
||||
|
||||
class Obj():
|
||||
val: t.CInt
|
||||
|
||||
|
||||
export def main() -> int:
|
||||
w32cmd.SetConsoleOutputCP(pagecode)
|
||||
w32cmd.SetConsoleCP(pagecode)
|
||||
print("=== Unary * / & (Deref/AddrOf) Test ===")
|
||||
|
||||
# --- Test 1: 标量 & 取地址 + * 解引用 ---
|
||||
x: int = 42
|
||||
px: int* = &x
|
||||
d: int = *px
|
||||
print(f"T1: x={x} *(&x)={d} (expect 42, 42)")
|
||||
if d == 42:
|
||||
print("T1 OK")
|
||||
else:
|
||||
print("T1 FAIL")
|
||||
|
||||
# --- Test 2: 通过指针写回(c.DerefAs 兼容形式) ---
|
||||
#*px = 100
|
||||
|
||||
#k: int**
|
||||
#l = *k
|
||||
c.DerefAs(px, 100)
|
||||
print(f"T2: after c.DerefAs(px, 100) x={x} (expect 100)")
|
||||
if x == 100:
|
||||
print("T2 OK")
|
||||
else:
|
||||
print("T2 FAIL")
|
||||
|
||||
# --- Test 3: 数组元素地址 &arr[i] + * 解引用 ---
|
||||
a: t.CArray[t.CInt, 4]
|
||||
a[0] = 7
|
||||
pa: t.CInt | t.CPtr = &a[0]
|
||||
v3: int = *pa
|
||||
print(f"T3: a[0]={a[0]} *&a[0]={v3} (expect 7, 7)")
|
||||
if v3 == 7:
|
||||
print("T3 OK")
|
||||
else:
|
||||
print("T3 FAIL")
|
||||
|
||||
# --- Test 4: 结构体字段地址 &s.f + * 解引用 ---
|
||||
s: TestStruct
|
||||
s.a = 10
|
||||
pf: t.CInt | t.CPtr = &s.a
|
||||
v4: int = *pf
|
||||
print(f"T4: s.a={s.a} *&s.a={v4} (expect 10, 10)")
|
||||
if v4 == 10:
|
||||
print("T4 OK")
|
||||
else:
|
||||
print("T4 FAIL")
|
||||
|
||||
# --- Test 5: &obj 对象指针(对象变量即指针) ---
|
||||
o: Obj
|
||||
o.val = 99
|
||||
po: Obj | t.CPtr = &o
|
||||
print(f"T5: o.val={o.val} &o->val={po.val} (expect 99, 99)")
|
||||
if po.val == 99:
|
||||
print("T5 OK")
|
||||
else:
|
||||
print("T5 FAIL")
|
||||
|
||||
print("=== Unary * / & Test Done ===")
|
||||
|
||||
# ============================================================
|
||||
# 类型系统收敛测试(阶段1a/1b/2/3)
|
||||
# 验证:正常库分析优先(from-import 别名、库 typedef 动态表),
|
||||
# t/c 库内部特判兜底(CInt/CBool/CPtr 等核心原语保留硬编码)。
|
||||
# ============================================================
|
||||
print("=== Type System Convergence Test ===")
|
||||
|
||||
# --- T6: from-import 别名反查(阶段1a)---
|
||||
# from t import CInt as MyInt → 裸名 MyInt 注解经别名反查 → i32
|
||||
a6: MyInt = 123
|
||||
# MyWord: t.CTypedef = MyInt → typedef 值引用别名 → 链式解析
|
||||
b6: MyWord = 456
|
||||
# from stdint import BYTE as MyByte → 裸名别名 → t.CUnsignedChar
|
||||
m6: MyByte = 65
|
||||
print(f"T6: MyInt={a6} MyWord={b6} MyByte={m6} (expect 123, 456, 65)")
|
||||
if a6 == 123 and b6 == 456 and m6 == 65:
|
||||
print("T6 OK")
|
||||
else:
|
||||
print("T6 FAIL")
|
||||
|
||||
# --- T7: 库 typedef 裸名解析(阶段1b/2)---
|
||||
# 裸名 BYTE/DWORD 走 CTypedef 动态表(stdint.vp 声明权威)
|
||||
bb7: BYTE = 200
|
||||
dd7: DWORD = 0x12345678
|
||||
# typedef 引用 typedef(MyDword = DWORD → CUInt32T)
|
||||
jj7: MyDword = 0xABCD
|
||||
# t/c 核心原语内部特判保留(t.CBool → i1 硬编码兜底)
|
||||
kk7: t.CBool = True
|
||||
print(f"T7: BYTE={bb7} DWORD={dd7} MyDword={jj7} CBool={kk7} (expect 200, 305419896, 43981, 1)")
|
||||
if bb7 == 200 and dd7 == 0x12345678 and jj7 == 0xABCD and kk7 == 1:
|
||||
print("T7 OK")
|
||||
else:
|
||||
print("T7 FAIL")
|
||||
|
||||
# --- T8: __sizeof__ 库 typedef(阶段3 尺寸联动)---
|
||||
s8a: int = BYTE.__sizeof__()
|
||||
s8b: int = DWORD.__sizeof__()
|
||||
s8c: int = MyWord.__sizeof__()
|
||||
s8d: int = t.CBool.__sizeof__()
|
||||
print(f"T8: sizeof(BYTE)={s8a} sizeof(DWORD)={s8b} sizeof(MyWord)={s8c} sizeof(CBool)={s8d} (expect 1, 4, 4, 1)")
|
||||
if s8a == 1 and s8b == 4 and s8c == 4 and s8d == 1:
|
||||
print("T8 OK")
|
||||
else:
|
||||
print("T8 FAIL")
|
||||
|
||||
# --- T9: typedef 联合(BYTE | t.CPtr → 指针包装,* 解引用)---
|
||||
p9: BYTE | t.CPtr = &bb7
|
||||
v9: BYTE = *p9
|
||||
print(f"T9: *(BYTE|CPtr)={v9} (expect 200)")
|
||||
if v9 == 200:
|
||||
print("T9 OK")
|
||||
else:
|
||||
print("T9 FAIL")
|
||||
|
||||
print("=== Type System Convergence Test Done ===")
|
||||
|
||||
main2.m()
|
||||
return 0
|
||||
@@ -1,4 +1,3 @@
|
||||
import t, c
|
||||
import stdio
|
||||
|
||||
|
||||
|
||||
@@ -5,14 +5,13 @@
|
||||
# 2) ZipFile("r") reads back: entry count / name / size / compress_size checks + per-member content compare
|
||||
# (CRC32 verification is done inside zipfile.read)
|
||||
# 3) Corrupt one payload byte of a stored member -> a second read must return None with error ZIP_ERR_CRC
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import stdlib
|
||||
import string
|
||||
import zipfile
|
||||
import w32.win32base as wb
|
||||
import w32.win32file as wf
|
||||
import win32.win32base as wb
|
||||
import win32.win32file as wf
|
||||
|
||||
|
||||
ZIP_PATH: str = "zip_roundtrip.zip"
|
||||
|
||||
Reference in new issue
Block a user