Files
TransPyC/lib/Shell/TransPyC.py
T
TermiNexus c83fc752c6 fix(sizeof,parse): 尺寸链去静默兜底,解析报错可定位,补 C 解析器缺口
StructGen: _get_struct_size/_get_align 去 opaque→8/ptr_size、未知→4 兜底并补 VectorType;LiteralStructType.fields→.elements(llvmlite 无 fields,必然 AttributeError)

HandlesClassDef: union 载荷尺寸经不存在的 ir.DataLayout 静默退化成 8 字节;HandlesExprCall/ExprBuiltin: sizeof 各静默 0 分支改 fail-fast,数组元素 sizeof 统一走 _get_struct_size

HandlesFor: nonlocal struct/array 堆分配不再退化成 malloc(8)

vast/vast_c: 补一元 * / & 解析,装饰器后 extern/export 分派修复,C 侧报错带 token 与行号;StubGen.Converter: 宏展开丢尾随空行修 .pyi 缩进非法

其余为 rawptr 迁移 / fail-fast 口径等历史改动一并入库
2026-09-26 19:27:22 +08:00

691 lines
30 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
import sys
import os
import vast as ast
import shlex
import datetime
import tempfile
import subprocess
from typing import Any
from lib.includes import c
from lib.includes import t
from lib.constants.config import (
DEFAULT_INPUT_FILE, DEFAULT_OUTPUT_FILE,
DEFAULT_COMPILE_COMMAND,
DEFAULT_COMPILE_FLAGS,
HELP_MESSAGE, DEFAULT_METADATA
)
from lib.utils.helpers import (
DetectFileType, ExecuteCommand,
AppendFileContent
)
from lib.core.SymbolUtils import ExpandSoftKeywords
from lib.core.VLogger import info, warning, error, success, debug
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.Shell.Serializer import SerializeSymbolTable, SymbolFile
from lib.Shell.Config import Config
class TransPyC:
"""TransPyC 主类"""
def __init__(self, code: str | None = None, debug: bool = False, triple: str | None = None, datalayout: str | None = None) -> None:
"""初始化TransPyC对象
Args:
code: 代码字符串
debug: 调试模式
triple: LLVM target triple (e.g. "x86_64-pc-linux-gnu")
datalayout: LLVM data layout string
"""
self.Args: dict[str, Any] = {}
self.HeaderFiles: list[str] = []
self.HelperFiles: list[str] = []
self.AnnotationFiles: list[str] = []
self.translator: Translator = Translator()
self.code: str | None = code
self.translator.Content = code
self.config: Config = Config()
self.translator.config = self.config
self.config.debug = debug
self.SymbolFiles: list[SymbolFile] = []
self.SliceLevel: int | str = 3
self.SliceCount: int = 0
self.SliceInfos: list[Any] = []
self.metadata: dict[str, Any] = DEFAULT_METADATA.copy()
self.triple: str | None = triple
self.datalayout: str | None = datalayout
self._source_module_sig_files: dict[str, Any] = {}
@staticmethod
def PreProcessSymbol(SymbolFile: SymbolFile, debug: bool = False) -> bytes | tuple[bytes, str]:
"""预处理符号文件,提取符号表并返回二进制数据
Args:
SymbolFile: SymbolFile对象,包含文件路径和类型信息
debug: 是否启用调试模式,如果为True,返回 (bytes, DebugInfo)
对于Python文件,DebugInfo包含p2c日志
对于C文件,DebugInfo包含基本处理信息
Returns:
如果debug为False: bytes - 序列化后的符号表二进制数据
如果debug为True: (bytes, str) - (二进制数据, 调试日志)
"""
translator: Translator = Translator()
DebugLogs: list[str] | str = []
try:
# 读取文件内容
if SymbolFile.FilePath:
with open(SymbolFile.FilePath, 'r', encoding=SymbolFile.encoding) as f:
content: str = f.read()
elif SymbolFile.CodeString:
content = SymbolFile.CodeString
else:
raise ValueError("SymbolFile must have either FilePath or CodeString")
# 根据文件类型处理
FileType: str | None = SymbolFile.FileType
if not FileType and SymbolFile.FilePath:
# 从文件路径推断类型
if SymbolFile.FilePath.endswith('.vp') or SymbolFile.FilePath.endswith('.py'):
FileType = 'py'
elif SymbolFile.FilePath.endswith('.c') or SymbolFile.FilePath.endswith('.h'):
FileType = 'c'
if FileType == 'py':
# Python文件处理
content = ExpandSoftKeywords(content)
translator.OriginalLines = content.split('\n')
translator.Content = content
# 设置调试文件(如果需要)
if debug:
DebugFile: str = SymbolFile.FilePath.replace('.py', '.p2c') if SymbolFile.FilePath else 'debug.p2c'
translator.SetDebugFile(DebugFile)
# 清空调试文件
with open(DebugFile, 'w', encoding=SymbolFile.encoding) as f:
f.write('')
# 解析AST并提取符号
tree: ast.Module = ast.parse(content, SymbolFile.FilePath or '<TransPyC:PreProcessSymbol>')
if debug:
with open(DebugFile, 'a', encoding=SymbolFile.encoding) as f:
f.write('=== AST Tree (Compact) ===\n')
f.write(ast.dump(tree))
f.write('\n\n')
# 遍历AST提取符号
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.ClassDef):
translator.SymbolTable[node.name] = {'type': 'struct', 'members': {}}
for item in node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
VarName: str = item.target.id
TypeInfo: CTypeInfo | None = translator.TypeMergeHandler.GetCTypeInfo(item.annotation) if item.annotation else None
VarType: str = TypeInfo.ToString() if TypeInfo else 'unknown'
IsPtr: bool = TypeInfo.IsPtr if TypeInfo else False
translator.SymbolTable[node.name]['members'][VarName] = {
'type': VarType,
'IsPtr': IsPtr
}
elif isinstance(node, ast.FunctionDef):
translator.SymbolTable[node.name] = {'type': 'function'}
elif isinstance(node, ast.AnnAssign):
if isinstance(node.target, ast.Name):
VarName: str = node.target.id
VarType: str = 'unknown'
IsPtr: bool = False
if node.annotation:
try:
TypeInfo: CTypeInfo | None = translator.TypeMergeHandler.GetCTypeInfo(node.annotation)
VarType = TypeInfo.ToString() if TypeInfo else 'unknown'
IsPtr = TypeInfo.IsPtr if TypeInfo else False
except:
pass
translator.SymbolTable[VarName] = {
'type': 'variable',
'declared_type': VarType,
'IsPtr': IsPtr
}
if debug:
with open(DebugFile, 'a', encoding=SymbolFile.encoding) as f:
f.write('=== Symbol Table ===\n')
f.write(str(translator.SymbolTable))
f.write('\n\n')
# 读取调试日志
with open(DebugFile, 'r', encoding=SymbolFile.encoding) as f:
DebugLogs = f.read()
elif FileType == 'c':
# C文件处理 - 使用现有的ParseHelperFiles逻辑
translator.ParseHelperFiles([SymbolFile.FilePath], SymbolFile.encoding)
if debug:
DebugLogs = f"=== C File Symbol Extraction ===\n"
DebugLogs += f"File: {SymbolFile.FilePath}\n"
DebugLogs += f"=== Symbol Table ===\n"
DebugLogs += str(translator.SymbolTable)
DebugLogs += "\n\n"
else:
raise ValueError(f"Unsupported file type: {FileType}")
# 序列化符号表
BinaryData: bytes = SerializeSymbolTable(translator.SymbolTable)
if debug:
return BinaryData, DebugLogs
return BinaryData
except Exception as e:
error_msg: str = f"Error processing symbol file: {e}"
if debug:
return b'', error_msg
raise RuntimeError(error_msg)
def ParseArgs(self) -> None:
"""解析命令行参数"""
I: int = 1
while I < len(sys.argv):
if sys.argv[I] == '-f':
if I + 1 < len(sys.argv):
self.Args['Input'] = sys.argv[I + 1]
I += 2
else:
error('-f requires an argument')
sys.exit(1)
elif sys.argv[I] == '-o':
if I + 1 < len(sys.argv):
self.Args['Output'] = sys.argv[I + 1]
I += 2
else:
error('-o requires an argument')
sys.exit(1)
elif sys.argv[I] == '-wh':
if I + 1 < len(sys.argv):
self.HeaderFiles = sys.argv[I + 1:]
break
else:
error('-wh requires arguments')
sys.exit(1)
elif sys.argv[I] == '-debug':
if I + 1 < len(sys.argv):
self.Args['Debug'] = sys.argv[I + 1]
I += 2
else:
error('-debug requires an argument')
sys.exit(1)
elif sys.argv[I] == '-cc':
# 编译命令
if I + 1 < len(sys.argv):
self.Args['CompileCommand'] = sys.argv[I + 1]
I += 2
else:
error('-cc requires an argument')
sys.exit(1)
elif sys.argv[I] == '-cflags':
# 编译标志
if I + 1 < len(sys.argv):
self.Args['CompileFlags'] = sys.argv[I + 1]
I += 2
else:
error('-cflags requires an argument')
sys.exit(1)
elif sys.argv[I] == '-run':
# 是否运行生成的程序
self.Args['Run'] = True
I += 1
elif sys.argv[I] == '-args':
# 运行时参数
if I + 1 < len(sys.argv):
self.Args['RunArgs'] = sys.argv[I + 1]
I += 2
else:
error('-args requires an argument')
sys.exit(1)
elif sys.argv[I] == '-level' or sys.argv[I] == '-l':
if I + 1 < len(sys.argv):
LevelArg: str = sys.argv[I + 1]
if LevelArg.isdigit():
self.Args['SliceLevel'] = int(LevelArg)
elif LevelArg == 's':
self.Args['SliceLevel'] = 's'
else:
self.Args['SliceLevel'] = 3
I += 1
else:
self.Args['SliceLevel'] = 3
elif sys.argv[I] == '-h':
# 辅助文件,用于解析符号信息
if I + 1 < len(sys.argv):
# 收集所有后续参数作为辅助文件,直到遇到下一个以-开头的参数
while I + 1 < len(sys.argv) and not sys.argv[I + 1].startswith('-'):
self.HelperFiles.append(sys.argv[I + 1])
I += 1
I += 1
else:
error('-h requires arguments')
sys.exit(1)
elif sys.argv[I] == '-presym':
# 预处理符号文件,生成.symbin文件
# 格式: -presym <InputFile> -o <OutputFile> [-debug <DebugFile>]
if I + 1 < len(sys.argv):
InputFile: str = sys.argv[I + 1]
I += 2
# 解析可选参数
OutputFile: str | None = None
DebugFile: str | None = None
while I < len(sys.argv) and sys.argv[I].startswith('-'):
if sys.argv[I] == '-o':
if I + 1 < len(sys.argv):
OutputFile = sys.argv[I + 1]
I += 2
else:
error('-o requires an argument')
sys.exit(1)
elif sys.argv[I] == '-debug':
if I + 1 < len(sys.argv):
DebugFile = sys.argv[I + 1]
I += 2
else:
error('-debug requires an argument')
sys.exit(1)
else:
break
# 如果没有指定输出文件,使用默认名称
if not OutputFile:
OutputFile = InputFile.replace('.vp', '.symbin').replace('.py', '.symbin').replace('.c', '.symbin')
# 执行预处理
self.Args['PreSym'] = {
'input': InputFile,
'output': OutputFile,
'debug': DebugFile
}
else:
error('-presym requires an argument')
sys.exit(1)
elif sys.argv[I] == '-e' or sys.argv[I] == '--encoding':
if I + 1 < len(sys.argv):
self.Args['Encoding'] = sys.argv[I + 1]
I += 2
else:
error('-e/--encoding requires an argument')
sys.exit(1)
elif sys.argv[I] == '--triple':
if I + 1 < len(sys.argv):
self.triple = sys.argv[I + 1]
I += 2
else:
error('--triple requires an argument')
sys.exit(1)
elif sys.argv[I] == '--datalayout':
if I + 1 < len(sys.argv):
self.datalayout = sys.argv[I + 1]
I += 2
else:
error('--datalayout requires an argument')
sys.exit(1)
elif sys.argv[I] == '--hotspot-sites':
# 调用点热点统计:可选路径(省略时默认 hotspot_sites.txt,运行期由
# 处理器按计数降序写入)。空串表示"已启用但未给路径"。
if I + 1 < len(sys.argv) and not sys.argv[I + 1].startswith('-'):
self.Args['HotspotSites'] = sys.argv[I + 1]
I += 2
else:
self.Args['HotspotSites'] = ''
I += 1
elif sys.argv[I].startswith('--hotspot-callees='):
# --hotspot-sites 白名单覆盖(逗号分隔的基名)
self.Args['HotspotCallees'] = sys.argv[I][len('--hotspot-callees='):]
I += 1
elif sys.argv[I] == '--hotspot-callees':
if I + 1 < len(sys.argv):
self.Args['HotspotCallees'] = sys.argv[I + 1]
I += 2
else:
error('--hotspot-callees requires an argument')
sys.exit(1)
elif sys.argv[I] == '--hotspot-sites-all':
# --hotspot-sites 对全部直接 call 点插桩(忽略白名单)
self.Args['HotspotSitesAll'] = True
I += 1
else:
error(f'Unknown argument {sys.argv[I]}')
sys.exit(1)
# 检查是否有预处理符号文件的请求,如果有则跳过输入输出检查
if 'PreSym' not in self.Args and ('Input' not in self.Args or 'Output' not in self.Args):
error('缺少参数')
info(HELP_MESSAGE)
sys.exit(1)
def CompileAndRun(self, OutputFile: str) -> None:
"""编译并运行生成的C代码"""
# 获取编译命令
CompileCmd: str = self.Args.get('CompileCommand', DEFAULT_COMPILE_COMMAND)
CompileFlags: str = self.Args.get('CompileFlags', DEFAULT_COMPILE_FLAGS)
# 构建编译命令(使用列表形式,避免 shell 注入)
FullCompileCmd: list[str] = shlex.split(CompileCmd) + shlex.split(CompileFlags) + [OutputFile, '-o', f'{OutputFile}.exe']
info(f'编译命令: {" ".join(FullCompileCmd)}')
# 执行编译命令
try:
CompileResult: subprocess.CompletedProcess[str] | None = ExecuteCommand(FullCompileCmd)
if CompileResult:
success('编译成功!')
# 检查是否需要运行
if self.Args.get('Run', False):
RunArgs: str = self.Args.get('RunArgs', '')
RunCmd: list[str] = [f'{OutputFile}.exe'] + (shlex.split(RunArgs) if RunArgs else [])
info(f'运行: {" ".join(RunCmd)}')
# 执行运行命令
RunResult: subprocess.CompletedProcess[str] | None = ExecuteCommand(RunCmd)
if RunResult:
info('执行输出:')
info(RunResult.stdout)
if RunResult.stderr:
warning('执行错误:')
warning(RunResult.stderr)
except Exception as e:
error(f'编译失败: {e}')
def WriteDebugInfo(self, content: str) -> None:
"""写入调试信息到指定文件"""
# 获取调试文件路径
if 'Debug' in self.Args:
DebugFile: str = self.Args['Debug']
else:
DebugFile: str = self.Args.get('Output', '').replace('.c', '.p2c')
if DebugFile:
AppendFileContent(DebugFile, content)
def PythonToC(self, InputFile: str, OutputFile: str) -> None:
"""Python到C的转换"""
# 获取编码参数
encoding: str = self.Args.get('Encoding', 'utf-8')
# 设置调试文件路径(使用 .p2c 扩展名)
if 'Debug' in self.Args:
DebugFile: str = self.Args['Debug']
else:
# 默认使用 .p2c 文件
DebugFile: str = OutputFile.replace('.c', '.p2c')
# 设置翻译器的调试文件
self.translator.SetDebugFile(DebugFile)
# 先清空调试文件
with open(DebugFile, 'w', encoding=encoding) as f:
f.write('')
# 解析辅助文件,提取符号信息
if self.HelperFiles:
self.translator.ParseHelperFiles(self.HelperFiles, encoding)
# 加载注解文件,提取类型定义
if self.AnnotationFiles:
self.translator.LoadAnnotationFiles(self.AnnotationFiles)
# 获取编码参数
encoding = self.Args.get('Encoding', 'utf-8')
with open(InputFile, 'r', encoding=encoding) as F:
Content: str = F.read()
# 软关键字展开:fn/fun/func/function -> def,供 ast.parse 使用
Content = ExpandSoftKeywords(Content)
# 保存原始代码行
self.translator.OriginalLines = Content.split('\n')
self.translator.Content = Content
# 解析Python代码为AST
Tree: ast.Module = ast.parse(Content, InputFile)
# 解析文件以提取类型信息(用于 EmbeddedAssignments)
self.translator.ParsePythonFile(InputFile, encoding)
# 写入AST树信息(压缩格式)
with open(DebugFile, 'a', encoding=encoding) as f:
f.write('=== AST Tree (Compact) ===\n')
f.write(ast.dump(Tree))
f.write('\n\n')
Target: str = 'llvm'
CCode: str = self.translator.GenerateCCode(Tree, target=Target)
timestamp: str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
filename: str = os.path.basename(OutputFile)
encoding = self.Args.get('Encoding', 'utf-8')
with open(OutputFile, 'w', encoding=encoding) as F:
F.write(CCode)
F.write('\n')
def CToPython(self, InputFile: str, OutputFile: str, HeaderFiles: list[str]) -> None:
"""C到Python的转换(暂时禁用)"""
warning("C到Python的转换功能暂时禁用,请使用Python到C的转换功能。")
def AddSymbol(self, SymbolFiles: SymbolFile | list[SymbolFile]) -> None:
"""添加符号文件
Args:
SymbolFiles: 符号文件或符号文件列表
"""
if isinstance(SymbolFiles, list):
self.SymbolFiles.extend(SymbolFiles)
else:
self.SymbolFiles.append(SymbolFiles)
# 收集文件路径和编码
HelperFiles: list[str] = []
encodings: list[str] = []
for SymbolFile in self.SymbolFiles:
FilePath: str | None = SymbolFile.FilePath
encoding: str = SymbolFile.encoding
if FilePath:
HelperFiles.append(FilePath)
encodings.append(encoding)
# 解析辅助文件
if HelperFiles:
# 暂时使用第一个文件的编码
encoding = encodings[0] if encodings else 'utf-8'
self.translator.ParseHelperFiles(HelperFiles, encoding)
def Convert(self, OutputFilename: str | None = None, SourceFilename: str | None = None, target: str = 'llvm') -> str | tuple[str, dict[str, Any]] | None:
"""转换代码
Args:
OutputFilename: 输出文件名(用于模板渲染)
SourceFilename: 源文件路径(用于设置CurrentFile,影响导入模块的查找)
target: 目标代码类型,仅支持 'llvm'
Returns:
如果debug是字符串,则返回生成的代码
如果debug是True,则返回生成的代码和调试信息
"""
if not self.code:
error('未提供代码')
return None
# 软关键字展开:fn/fun/func/function -> def,供 ast.parse 使用
self.code = ExpandSoftKeywords(self.code)
from lib.core.Handles.HandlesImports import ImportHandle
ImportHandle._struct_Load_cache.clear()
# 如果提供了 SourceFilename,先设置 CurrentFile
# 这样导入模块时会相对于源文件所在目录查找
if SourceFilename:
self.translator.CurrentFile = SourceFilename
# 加载注解文件,提取类型定义
if self.AnnotationFiles:
self.translator.LoadAnnotationFiles(self.AnnotationFiles)
# 保存原始代码行
self.translator.OriginalLines = self.code.split('\n')
# 解析Python代码为AST
Tree: ast.Module = ast.parse(self.code, SourceFilename or '<TransPyC:Convert>')
# 从源代码直接预扫描 import 语句,注册别名
# 注意:不能依赖 Tree 中的 import 节点,因为 ParsePythonFile 可能修改了 AST
if not getattr(self.translator, '_ImportedModules', None):
self.translator._ImportedModules = set()
_prescan_tree: ast.Module = ast.parse(self.code, SourceFilename or '<TransPyC:Convert>')
for _node in ast.iter_child_nodes(_prescan_tree):
if isinstance(_node, ast.Import):
for _alias in _node.names:
_name: str = _alias.name
if _name in ('c', 't'):
continue
self.translator._ImportedModules.add(_name)
if _alias.asname:
self.translator.SymbolTable.import_aliases[_alias.asname] = _name
elif isinstance(_node, ast.ImportFrom):
_module_name: str | None = _node.module
if _module_name and _module_name not in ('c', 't'):
self.translator._ImportedModules.add(_module_name)
for _alias in _node.names:
if _alias.asname:
self.translator.SymbolTable.import_aliases[_alias.asname] = f"{_module_name}.{_alias.name}"
# 解析代码以提取类型信息(用于 EmbeddedAssignments 和 TypedefAssignments)
# 创建临时文件路径用于解析
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False, encoding='utf-8') as f:
f.write(self.code)
TempFile: str = f.name
try:
# UpdateCurrentFile=False 表示不修改 CurrentFile
if SourceFilename:
self.translator.ParsePythonFile(TempFile, UpdateCurrentFile=False)
else:
self.translator.ParsePythonFile(TempFile)
finally:
os.unlink(TempFile)
timestamp: str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
if self.triple:
self.translator.triple = self.triple
if self.datalayout:
self.translator.datalayout = self.datalayout
# 生成代码
code: str = self.translator.GenerateCCode(Tree, target='llvm')
filename: str = os.path.basename(OutputFilename) if OutputFilename else 'generated.ll'
# 处理调试信息
if isinstance(self.config.debug, str):
# 如果debug是字符串,写入调试信息到文件
with open(self.config.debug, 'w', encoding='utf-8') as f:
f.write('=== Symbol Table ===\n')
f.write(str(self.translator.SymbolTable) + '\n\n')
f.write('=== AST Tree ===\n')
f.write(ast.dump(Tree, indent=2) + '\n\n')
f.write('=== Export Table ===\n')
f.write(self.translator.Exportable.to_json() + '\n\n')
f.write('=== Generated Code ===\n')
f.write(code + '\n')
return code
elif self.config.debug:
# 如果debug是True,返回生成的代码和调试信息
DebugInfo: dict[str, Any] = {
'SymbolTable': self.translator.SymbolTable,
'ast_tree': ast.dump(Tree, indent=2),
'Exportable': self.translator.Exportable.to_dict(),
'generated_code': code
}
return code, DebugInfo
else:
# 如果debug是False,只返回生成的代码
return code
def Run(self) -> None:
"""主运行函数"""
# 检查是否有命令行参数
if len(sys.argv) > 1:
# 有命令行参数,使用 ParseArgs 方法解析
self.ParseArgs()
# 调用点热点统计与每函数计时(--hotspot-sites):None=未启用(零影响);
# ''=启用但未给路径(默认 hotspot_sites.txt)。注册走种子单模块路径
# (main 入口注册);计时结果写到同目录 hotspot_time.txt。
HotspotSites: str | None = self.Args.get('HotspotSites')
if HotspotSites is not None:
if HotspotSites == '':
HotspotSites = 'hotspot_sites.txt'
self.translator.HotspotSitesFile = os.path.abspath(HotspotSites)
self.translator.HotspotSitesAll = bool(self.Args.get('HotspotSitesAll'))
HotspotCallees: str | None = self.Args.get('HotspotCallees')
if HotspotCallees:
self.translator.HotspotCallees = [c.strip() for c in HotspotCallees.split(',') if c.strip()]
# 检查是否有预处理符号文件的请求
if 'PreSym' in self.Args:
PresymConfig: dict[str, Any] = self.Args['PreSym']
InputFile: str = PresymConfig['input']
OutputFile: str = PresymConfig['output']
DebugFile: str | None = PresymConfig['debug']
# 获取编码参数
encoding: str = self.Args.get('Encoding', 'utf-8')
# 推断文件类型
FileType: str | None = 'py' if (InputFile.endswith('.vp') or InputFile.endswith('.py')) else 'c' if InputFile.endswith('.c') else None
# 创建 SymbolFile 对象,传入编码参数
SymbolFile: SymbolFile = SymbolFile(file=InputFile, type=FileType, encoding=encoding)
# 调用 PreProcessSymbol
if DebugFile:
BinaryData: bytes
DebugInfo: str
BinaryData, DebugInfo = TransPyC.PreProcessSymbol(SymbolFile, debug=True)
# 写入调试文件
with open(DebugFile, 'w', encoding=encoding) as f:
f.write(DebugInfo)
info(f"调试信息写入: {DebugFile}")
else:
BinaryData: bytes = TransPyC.PreProcessSymbol(SymbolFile, debug=False)
# 写入二进制符号文件
with open(OutputFile, 'wb') as f:
f.write(BinaryData)
success(f"符号文件生成: {OutputFile}")
return
InputFile: str = self.Args['Input']
OutputFile: str = self.Args['Output']
else:
# 没有命令行参数,使用默认的测试文件名称
InputFile: str = DEFAULT_INPUT_FILE
OutputFile: str = DEFAULT_OUTPUT_FILE
info('使用默认测试文件: test.vp -> test.c')
FileType: str = DetectFileType(InputFile)
if FileType in ('.vp', '.py'):
self.PythonToC(InputFile, OutputFile)
# 检查是否需要编译和运行
if 'CompileCommand' in self.Args or self.Args.get('Run', False):
self.CompileAndRun(OutputFile)
elif FileType == '.c':
self.CToPython(InputFile, OutputFile, self.HeaderFiles)
else:
error(f'不支持的文件类型: {FileType}')
sys.exit(1)