修复了大量存在的问题,增加了假鸭子类型等等机制
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
class Config:
|
||||
"""配置类"""
|
||||
def __init__(self):
|
||||
self.debug = False
|
||||
self.mode = 'relaxed' # 'relaxed' 或 'strict'
|
||||
def __init__(self) -> None:
|
||||
self.debug: bool = False
|
||||
self.mode: str = 'relaxed' # 'relaxed' 或 'strict'
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import struct
|
||||
from typing import Any
|
||||
|
||||
|
||||
def SerializeSymbolTable(SymbolTable: dict) -> bytes:
|
||||
def SerializeSymbolTable(SymbolTable: dict[str, Any]) -> bytes:
|
||||
"""将符号表序列化为二进制格式
|
||||
|
||||
格式:
|
||||
@@ -15,14 +18,14 @@ def SerializeSymbolTable(SymbolTable: dict) -> bytes:
|
||||
Returns:
|
||||
二进制字节数据
|
||||
"""
|
||||
JsonData = json.dumps(SymbolTable, ensure_ascii=False).encode('utf-8')
|
||||
length = len(JsonData)
|
||||
JsonData: bytes = json.dumps(SymbolTable, ensure_ascii=False).encode('utf-8')
|
||||
length: int = len(JsonData)
|
||||
# 使用4字节小端序整数表示长度
|
||||
header = struct.pack('<I', length)
|
||||
header: bytes = struct.pack('<I', length)
|
||||
return header + JsonData
|
||||
|
||||
|
||||
def deSerializeSymbolTable(data: bytes) -> dict:
|
||||
def deSerializeSymbolTable(data: bytes) -> dict[str, Any]:
|
||||
"""从二进制数据反序列化符号表
|
||||
|
||||
Args:
|
||||
@@ -34,15 +37,15 @@ def deSerializeSymbolTable(data: bytes) -> dict:
|
||||
if len(data) < 4:
|
||||
raise ValueError("Invalid symbin file: data too short")
|
||||
# 解析4字节长度头(小端序)
|
||||
length = struct.unpack('<I', data[:4])[0]
|
||||
JsonData = data[4:4+length]
|
||||
length: int = struct.unpack('<I', data[:4])[0]
|
||||
JsonData: bytes = data[4:4+length]
|
||||
return json.loads(JsonData.decode('utf-8'))
|
||||
|
||||
|
||||
class SymbolFile:
|
||||
"""符号文件类,用于解析和存储符号信息"""
|
||||
|
||||
def __init__(self, file=None, string=None, type=None, encoding='utf-8'):
|
||||
def __init__(self, file: str | None = None, string: str | None = None, type: str | None = None, encoding: str = 'utf-8') -> None:
|
||||
"""初始化SymbolFile对象
|
||||
|
||||
Args:
|
||||
@@ -51,8 +54,8 @@ class SymbolFile:
|
||||
type: 文件类型,支持"c"或"py"
|
||||
encoding: 文件编码
|
||||
"""
|
||||
self.FilePath = file
|
||||
self.CodeString = string
|
||||
self.FileType = type
|
||||
self.encoding = encoding
|
||||
self.symbols = {}
|
||||
self.FilePath: str | None = file
|
||||
self.CodeString: str | None = string
|
||||
self.FileType: str | None = type
|
||||
self.encoding: str = encoding
|
||||
self.symbols: dict[str, Any] = {}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import os
|
||||
import ast
|
||||
import json
|
||||
import shlex
|
||||
import struct
|
||||
import datetime
|
||||
import tempfile
|
||||
import subprocess
|
||||
from typing import Any
|
||||
# 添加lib目录到Python路径
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'lib', 'includes'))
|
||||
from lib.includes import c
|
||||
@@ -17,7 +24,9 @@ from lib.utils.helpers import (
|
||||
DetectFileType, ExecuteCommand,
|
||||
AppendFileContent
|
||||
)
|
||||
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, deSerializeSymbolTable, SymbolFile
|
||||
from lib.Shell.Config import Config
|
||||
|
||||
@@ -25,7 +34,7 @@ from lib.Shell.Config import Config
|
||||
class TransPyC:
|
||||
"""TransPyC 主类"""
|
||||
|
||||
def __init__(self, code=None, debug=False, triple=None, datalayout=None):
|
||||
def __init__(self, code: str | None = None, debug: bool = False, triple: str | None = None, datalayout: str | None = None) -> None:
|
||||
"""初始化TransPyC对象
|
||||
|
||||
Args:
|
||||
@@ -34,27 +43,27 @@ class TransPyC:
|
||||
triple: LLVM target triple (e.g. "x86_64-pc-linux-gnu")
|
||||
datalayout: LLVM data layout string
|
||||
"""
|
||||
self.Args = {}
|
||||
self.HeaderFiles = []
|
||||
self.HelperFiles = []
|
||||
self.AnnotationFiles = []
|
||||
self.translator = Translator()
|
||||
self.code = code
|
||||
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()
|
||||
self.config: Config = Config()
|
||||
self.translator.config = self.config
|
||||
self.config.debug = debug
|
||||
self.SymbolFiles = []
|
||||
self.SliceLevel = 3
|
||||
self.SliceCount = 0
|
||||
self.SliceInfos = []
|
||||
self.metadata = DEFAULT_METADATA.copy()
|
||||
self.triple = triple
|
||||
self.datalayout = datalayout
|
||||
self._source_module_sig_files = {}
|
||||
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, debug=False):
|
||||
def PreProcessSymbol(SymbolFile: SymbolFile, debug: bool = False) -> bytes | tuple[bytes, str]:
|
||||
"""预处理符号文件,提取符号表并返回二进制数据
|
||||
|
||||
Args:
|
||||
@@ -67,21 +76,21 @@ class TransPyC:
|
||||
如果debug为False: bytes - 序列化后的符号表二进制数据
|
||||
如果debug为True: (bytes, str) - (二进制数据, 调试日志)
|
||||
"""
|
||||
translator = Translator()
|
||||
DebugLogs = []
|
||||
translator: Translator = Translator()
|
||||
DebugLogs: list[str] | str = []
|
||||
|
||||
try:
|
||||
# 读取文件内容
|
||||
if SymbolFile.FilePath:
|
||||
with open(SymbolFile.FilePath, 'r', encoding=SymbolFile.encoding) as f:
|
||||
content = f.read()
|
||||
content: str = f.read()
|
||||
elif SymbolFile.CodeString:
|
||||
content = SymbolFile.CodeString
|
||||
else:
|
||||
raise ValueError("SymbolFile must have either FilePath or CodeString")
|
||||
|
||||
# 根据文件类型处理
|
||||
FileType = SymbolFile.FileType
|
||||
FileType: str | None = SymbolFile.FileType
|
||||
if not FileType and SymbolFile.FilePath:
|
||||
# 从文件路径推断类型
|
||||
if SymbolFile.FilePath.endswith('.py'):
|
||||
@@ -96,14 +105,14 @@ class TransPyC:
|
||||
|
||||
# 设置调试文件(如果需要)
|
||||
if debug:
|
||||
DebugFile = SymbolFile.FilePath.replace('.py', '.p2c') if SymbolFile.FilePath else 'debug.p2c'
|
||||
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.parse(content)
|
||||
tree: ast.Module = ast.parse(content)
|
||||
|
||||
if debug:
|
||||
with open(DebugFile, 'a', encoding=SymbolFile.encoding) as f:
|
||||
@@ -117,10 +126,10 @@ class TransPyC:
|
||||
translator.SymbolTable[node.name] = {'type': 'struct', 'members': {}}
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
VarName = item.target.id
|
||||
TypeInfo = translator.TypeMergeHandler.GetCTypeInfo(item.annotation) if item.annotation else None
|
||||
VarType = TypeInfo.ToString() if TypeInfo else 'unknown'
|
||||
IsPtr = TypeInfo.IsPtr if TypeInfo else False
|
||||
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
|
||||
@@ -129,12 +138,12 @@ class TransPyC:
|
||||
translator.SymbolTable[node.name] = {'type': 'function'}
|
||||
elif isinstance(node, ast.AnnAssign):
|
||||
if isinstance(node.target, ast.Name):
|
||||
VarName = node.target.id
|
||||
VarType = 'unknown'
|
||||
IsPtr = False
|
||||
VarName: str = node.target.id
|
||||
VarType: str = 'unknown'
|
||||
IsPtr: bool = False
|
||||
if node.annotation:
|
||||
try:
|
||||
TypeInfo = translator.TypeMergeHandler.GetCTypeInfo(node.annotation)
|
||||
TypeInfo: CTypeInfo | None = translator.TypeMergeHandler.GetCTypeInfo(node.annotation)
|
||||
VarType = TypeInfo.ToString() if TypeInfo else 'unknown'
|
||||
IsPtr = TypeInfo.IsPtr if TypeInfo else False
|
||||
except:
|
||||
@@ -168,49 +177,49 @@ class TransPyC:
|
||||
raise ValueError(f"Unsupported file type: {FileType}")
|
||||
|
||||
# 序列化符号表
|
||||
BinaryData = SerializeSymbolTable(translator.SymbolTable)
|
||||
BinaryData: bytes = SerializeSymbolTable(translator.SymbolTable)
|
||||
|
||||
if debug:
|
||||
return BinaryData, DebugLogs
|
||||
return BinaryData
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error processing symbol file: {e}"
|
||||
error_msg: str = f"Error processing symbol file: {e}"
|
||||
if debug:
|
||||
return b'', error_msg
|
||||
raise RuntimeError(error_msg)
|
||||
|
||||
def ParseArgs(self):
|
||||
def ParseArgs(self) -> None:
|
||||
"""解析命令行参数"""
|
||||
I = 1
|
||||
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:
|
||||
print(f'Error: -f requires an argument')
|
||||
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:
|
||||
print(f'Error: -o requires an argument')
|
||||
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:
|
||||
print(f'Error: -wh requires arguments')
|
||||
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:
|
||||
print(f'Error: -debug requires an argument')
|
||||
error('-debug requires an argument')
|
||||
sys.exit(1)
|
||||
elif sys.argv[I] == '-cc':
|
||||
# 编译命令
|
||||
@@ -218,7 +227,7 @@ class TransPyC:
|
||||
self.Args['CompileCommand'] = sys.argv[I + 1]
|
||||
I += 2
|
||||
else:
|
||||
print(f'Error: -cc requires an argument')
|
||||
error('-cc requires an argument')
|
||||
sys.exit(1)
|
||||
elif sys.argv[I] == '-cflags':
|
||||
# 编译标志
|
||||
@@ -226,7 +235,7 @@ class TransPyC:
|
||||
self.Args['CompileFlags'] = sys.argv[I + 1]
|
||||
I += 2
|
||||
else:
|
||||
print(f'Error: -cflags requires an argument')
|
||||
error('-cflags requires an argument')
|
||||
sys.exit(1)
|
||||
elif sys.argv[I] == '-run':
|
||||
# 是否运行生成的程序
|
||||
@@ -238,11 +247,11 @@ class TransPyC:
|
||||
self.Args['RunArgs'] = sys.argv[I + 1]
|
||||
I += 2
|
||||
else:
|
||||
print(f'Error: -args requires an argument')
|
||||
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 = sys.argv[I + 1]
|
||||
LevelArg: str = sys.argv[I + 1]
|
||||
if LevelArg.isdigit():
|
||||
self.Args['SliceLevel'] = int(LevelArg)
|
||||
elif LevelArg == 's':
|
||||
@@ -261,32 +270,32 @@ class TransPyC:
|
||||
I += 1
|
||||
I += 1
|
||||
else:
|
||||
print(f'Error: -h requires arguments')
|
||||
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 = sys.argv[I + 1]
|
||||
InputFile: str = sys.argv[I + 1]
|
||||
I += 2
|
||||
|
||||
# 解析可选参数
|
||||
OutputFile = None
|
||||
DebugFile = None
|
||||
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:
|
||||
print(f'Error: -o requires an argument')
|
||||
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:
|
||||
print(f'Error: -debug requires an argument')
|
||||
error('-debug requires an argument')
|
||||
sys.exit(1)
|
||||
else:
|
||||
break
|
||||
@@ -302,94 +311,94 @@ class TransPyC:
|
||||
'debug': DebugFile
|
||||
}
|
||||
else:
|
||||
print(f'Error: -presym requires an argument')
|
||||
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:
|
||||
print(f'Error: -e/--encoding requires an argument')
|
||||
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:
|
||||
print(f'Error: --triple requires an argument')
|
||||
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:
|
||||
print(f'Error: --datalayout requires an argument')
|
||||
error('--datalayout requires an argument')
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(f'Error: Unknown argument {sys.argv[I]}')
|
||||
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):
|
||||
print(ERROR_MESSAGES['MISSING_ARGS'])
|
||||
print(HELP_MESSAGE)
|
||||
error('缺少参数')
|
||||
info(HELP_MESSAGE)
|
||||
sys.exit(1)
|
||||
|
||||
def CompileAndRun(self, OutputFile):
|
||||
def CompileAndRun(self, OutputFile: str) -> None:
|
||||
"""编译并运行生成的C代码"""
|
||||
# 获取编译命令
|
||||
CompileCmd = self.Args.get('CompileCommand', DEFAULT_COMPILE_COMMAND)
|
||||
CompileFlags = self.Args.get('CompileFlags', DEFAULT_COMPILE_FLAGS)
|
||||
CompileCmd: str = self.Args.get('CompileCommand', DEFAULT_COMPILE_COMMAND)
|
||||
CompileFlags: str = self.Args.get('CompileFlags', DEFAULT_COMPILE_FLAGS)
|
||||
|
||||
# 构建编译命令
|
||||
FullCompileCmd = f'{CompileCmd} {CompileFlags} {OutputFile} -o {OutputFile}.exe'
|
||||
print(f'Compiling: {FullCompileCmd}')
|
||||
# 构建编译命令(使用列表形式,避免 shell 注入)
|
||||
FullCompileCmd: list[str] = shlex.split(CompileCmd) + shlex.split(CompileFlags) + [OutputFile, '-o', f'{OutputFile}.exe']
|
||||
info(f'编译命令: {" ".join(FullCompileCmd)}')
|
||||
|
||||
# 执行编译命令
|
||||
try:
|
||||
CompileResult = ExecuteCommand(FullCompileCmd)
|
||||
CompileResult: subprocess.CompletedProcess[str] | None = ExecuteCommand(FullCompileCmd)
|
||||
if CompileResult:
|
||||
print('Compilation successful!')
|
||||
success('编译成功!')
|
||||
|
||||
# 检查是否需要运行
|
||||
if self.Args.get('Run', False):
|
||||
RunArgs = self.Args.get('RunArgs', '')
|
||||
RunCmd = f'{OutputFile}.exe {RunArgs}'.strip()
|
||||
print(f'Running: {RunCmd}')
|
||||
RunArgs: str = self.Args.get('RunArgs', '')
|
||||
RunCmd: list[str] = [f'{OutputFile}.exe'] + (shlex.split(RunArgs) if RunArgs else [])
|
||||
info(f'运行: {" ".join(RunCmd)}')
|
||||
|
||||
# 执行运行命令
|
||||
RunResult = ExecuteCommand(RunCmd)
|
||||
RunResult: subprocess.CompletedProcess[str] | None = ExecuteCommand(RunCmd)
|
||||
if RunResult:
|
||||
print('Execution output:')
|
||||
print(RunResult.stdout)
|
||||
info('执行输出:')
|
||||
info(RunResult.stdout)
|
||||
if RunResult.stderr:
|
||||
print('Execution errors:')
|
||||
print(RunResult.stderr)
|
||||
warning('执行错误:')
|
||||
warning(RunResult.stderr)
|
||||
except Exception as e:
|
||||
print(f'{ERROR_MESSAGES["COMPILE_FAILED"]}: {e}')
|
||||
error(f'编译失败: {e}')
|
||||
|
||||
def WriteDebugInfo(self, content):
|
||||
def WriteDebugInfo(self, content: str) -> None:
|
||||
"""写入调试信息到指定文件"""
|
||||
# 获取调试文件路径
|
||||
if 'Debug' in self.Args:
|
||||
DebugFile = self.Args['Debug']
|
||||
DebugFile: str = self.Args['Debug']
|
||||
else:
|
||||
DebugFile = self.Args.get('Output', '').replace('.c', '.p2c')
|
||||
DebugFile: str = self.Args.get('Output', '').replace('.c', '.p2c')
|
||||
|
||||
if DebugFile:
|
||||
AppendFileContent(DebugFile, content)
|
||||
|
||||
def PythonToC(self, InputFile, OutputFile):
|
||||
def PythonToC(self, InputFile: str, OutputFile: str) -> None:
|
||||
"""Python到C的转换"""
|
||||
# 获取编码参数
|
||||
encoding = self.Args.get('Encoding', 'utf-8')
|
||||
encoding: str = self.Args.get('Encoding', 'utf-8')
|
||||
|
||||
# 设置调试文件路径(使用 .p2c 扩展名)
|
||||
if 'Debug' in self.Args:
|
||||
DebugFile = self.Args['Debug']
|
||||
DebugFile: str = self.Args['Debug']
|
||||
else:
|
||||
# 默认使用 .p2c 文件
|
||||
DebugFile = OutputFile.replace('.c', '.p2c')
|
||||
DebugFile: str = OutputFile.replace('.c', '.p2c')
|
||||
|
||||
# 设置翻译器的调试文件
|
||||
self.translator.SetDebugFile(DebugFile)
|
||||
@@ -409,14 +418,14 @@ class TransPyC:
|
||||
# 获取编码参数
|
||||
encoding = self.Args.get('Encoding', 'utf-8')
|
||||
with open(InputFile, 'r', encoding=encoding) as F:
|
||||
Content = F.read()
|
||||
Content: str = F.read()
|
||||
|
||||
# 保存原始代码行
|
||||
self.translator.OriginalLines = Content.split('\n')
|
||||
self.translator.Content = Content
|
||||
|
||||
# 解析Python代码为AST
|
||||
Tree = ast.parse(Content)
|
||||
Tree: ast.Module = ast.parse(Content)
|
||||
|
||||
# 解析文件以提取类型信息(用于 EmbeddedAssignments)
|
||||
self.translator.ParsePythonFile(InputFile, encoding)
|
||||
@@ -427,23 +436,22 @@ class TransPyC:
|
||||
f.write(ast.dump(Tree))
|
||||
f.write('\n\n')
|
||||
|
||||
Target = 'llvm'
|
||||
CCode = self.translator.GenerateCCode(Tree, target=Target)
|
||||
Target: str = 'llvm'
|
||||
CCode: str = self.translator.GenerateCCode(Tree, target=Target)
|
||||
|
||||
import datetime
|
||||
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
filename = os.path.basename(OutputFile)
|
||||
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, OutputFile, HeaderFiles):
|
||||
def CToPython(self, InputFile: str, OutputFile: str, HeaderFiles: list[str]) -> None:
|
||||
"""C到Python的转换(暂时禁用)"""
|
||||
print("C到Python的转换功能暂时禁用,请使用Python到C的转换功能。")
|
||||
warning("C到Python的转换功能暂时禁用,请使用Python到C的转换功能。")
|
||||
|
||||
def AddSymbol(self, SymbolFiles):
|
||||
def AddSymbol(self, SymbolFiles: SymbolFile | list[SymbolFile]) -> None:
|
||||
"""添加符号文件
|
||||
|
||||
Args:
|
||||
@@ -455,11 +463,11 @@ class TransPyC:
|
||||
self.SymbolFiles.append(SymbolFiles)
|
||||
|
||||
# 收集文件路径和编码
|
||||
HelperFiles = []
|
||||
encodings = []
|
||||
HelperFiles: list[str] = []
|
||||
encodings: list[str] = []
|
||||
for SymbolFile in self.SymbolFiles:
|
||||
FilePath = SymbolFile.FilePath
|
||||
encoding = SymbolFile.encoding
|
||||
FilePath: str | None = SymbolFile.FilePath
|
||||
encoding: str = SymbolFile.encoding
|
||||
if FilePath:
|
||||
HelperFiles.append(FilePath)
|
||||
encodings.append(encoding)
|
||||
@@ -470,7 +478,7 @@ class TransPyC:
|
||||
encoding = encodings[0] if encodings else 'utf-8'
|
||||
self.translator.ParseHelperFiles(HelperFiles, encoding)
|
||||
|
||||
def Convert(self, OutputFilename=None, SourceFilename=None, target='llvm'):
|
||||
def Convert(self, OutputFilename: str | None = None, SourceFilename: str | None = None, target: str = 'llvm') -> str | tuple[str, dict[str, Any]] | None:
|
||||
"""转换代码
|
||||
|
||||
Args:
|
||||
@@ -483,7 +491,7 @@ class TransPyC:
|
||||
如果debug是True,则返回生成的代码和调试信息
|
||||
"""
|
||||
if not self.code:
|
||||
print('Error: No code provided')
|
||||
error('未提供代码')
|
||||
return None
|
||||
|
||||
from lib.core.Handles.HandlesImports import ImportHandle
|
||||
@@ -502,24 +510,24 @@ class TransPyC:
|
||||
self.translator.OriginalLines = self.code.split('\n')
|
||||
|
||||
# 解析Python代码为AST
|
||||
Tree = ast.parse(self.code)
|
||||
Tree: ast.Module = ast.parse(self.code)
|
||||
|
||||
# 从源代码直接预扫描 import 语句,注册别名
|
||||
# 注意:不能依赖 Tree 中的 import 节点,因为 ParsePythonFile 可能修改了 AST
|
||||
if not getattr(self.translator, '_ImportedModules', None):
|
||||
self.translator._ImportedModules = set()
|
||||
_prescan_tree = ast.parse(self.code)
|
||||
_prescan_tree: ast.Module = ast.parse(self.code)
|
||||
for _node in ast.iter_child_nodes(_prescan_tree):
|
||||
if isinstance(_node, ast.Import):
|
||||
for _alias in _node.names:
|
||||
_name = _alias.name
|
||||
_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 = _node.module
|
||||
_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:
|
||||
@@ -528,11 +536,9 @@ class TransPyC:
|
||||
|
||||
# 解析代码以提取类型信息(用于 EmbeddedAssignments 和 TypedefAssignments)
|
||||
# 创建临时文件路径用于解析
|
||||
import tempfile
|
||||
import os
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False, encoding='utf-8') as f:
|
||||
f.write(self.code)
|
||||
TempFile = f.name
|
||||
TempFile: str = f.name
|
||||
try:
|
||||
# UpdateCurrentFile=False 表示不修改 CurrentFile
|
||||
if SourceFilename:
|
||||
@@ -542,8 +548,7 @@ class TransPyC:
|
||||
finally:
|
||||
os.unlink(TempFile)
|
||||
|
||||
import datetime
|
||||
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
timestamp: str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
if self.triple:
|
||||
self.translator.triple = self.triple
|
||||
@@ -551,8 +556,8 @@ class TransPyC:
|
||||
self.translator.datalayout = self.datalayout
|
||||
|
||||
# 生成代码
|
||||
code = self.translator.GenerateCCode(Tree, target='llvm')
|
||||
filename = os.path.basename(OutputFilename) if OutputFilename else 'generated.ll'
|
||||
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):
|
||||
@@ -569,7 +574,7 @@ class TransPyC:
|
||||
return code
|
||||
elif self.config.debug:
|
||||
# 如果debug是True,返回生成的代码和调试信息
|
||||
DebugInfo = {
|
||||
DebugInfo: dict[str, Any] = {
|
||||
'SymbolTable': self.translator.SymbolTable,
|
||||
'ast_tree': ast.dump(Tree, indent=2),
|
||||
'Exportable': self.translator.Exportable.to_dict(),
|
||||
@@ -580,7 +585,7 @@ class TransPyC:
|
||||
# 如果debug是False,只返回生成的代码
|
||||
return code
|
||||
|
||||
def Run(self):
|
||||
def Run(self) -> None:
|
||||
"""主运行函数"""
|
||||
# 检查是否有命令行参数
|
||||
if len(sys.argv) > 1:
|
||||
@@ -589,46 +594,48 @@ class TransPyC:
|
||||
|
||||
# 检查是否有预处理符号文件的请求
|
||||
if 'PreSym' in self.Args:
|
||||
PresymConfig = self.Args['PreSym']
|
||||
InputFile = PresymConfig['input']
|
||||
OutputFile = PresymConfig['output']
|
||||
DebugFile = PresymConfig['debug']
|
||||
PresymConfig: dict[str, Any] = self.Args['PreSym']
|
||||
InputFile: str = PresymConfig['input']
|
||||
OutputFile: str = PresymConfig['output']
|
||||
DebugFile: str | None = PresymConfig['debug']
|
||||
|
||||
# 获取编码参数
|
||||
encoding = self.Args.get('Encoding', 'utf-8')
|
||||
encoding: str = self.Args.get('Encoding', 'utf-8')
|
||||
|
||||
# 推断文件类型
|
||||
FileType = 'py' if InputFile.endswith('.py') else 'c' if InputFile.endswith('.c') else None
|
||||
FileType: str | None = 'py' if InputFile.endswith('.py') else 'c' if InputFile.endswith('.c') else None
|
||||
|
||||
# 创建 SymbolFile 对象,传入编码参数
|
||||
SymbolFile = SymbolFile(file=InputFile, type=FileType, encoding=encoding)
|
||||
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)
|
||||
print(f"Debug info written to: {DebugFile}")
|
||||
info(f"调试信息写入: {DebugFile}")
|
||||
else:
|
||||
BinaryData = TransPyC.PreProcessSymbol(SymbolFile, debug=False)
|
||||
BinaryData: bytes = TransPyC.PreProcessSymbol(SymbolFile, debug=False)
|
||||
|
||||
# 写入二进制符号文件
|
||||
with open(OutputFile, 'wb') as f:
|
||||
f.write(BinaryData)
|
||||
|
||||
print(f"Symbol file generated: {OutputFile}")
|
||||
success(f"符号文件生成: {OutputFile}")
|
||||
return
|
||||
|
||||
InputFile = self.Args['Input']
|
||||
OutputFile = self.Args['Output']
|
||||
InputFile: str = self.Args['Input']
|
||||
OutputFile: str = self.Args['Output']
|
||||
else:
|
||||
# 没有命令行参数,使用默认的测试文件名称
|
||||
InputFile = DEFAULT_INPUT_FILE
|
||||
OutputFile = DEFAULT_OUTPUT_FILE
|
||||
print('Using default test files: test.py -> test.c')
|
||||
InputFile: str = DEFAULT_INPUT_FILE
|
||||
OutputFile: str = DEFAULT_OUTPUT_FILE
|
||||
info('使用默认测试文件: test.py -> test.c')
|
||||
|
||||
FileType = DetectFileType(InputFile)
|
||||
FileType: str = DetectFileType(InputFile)
|
||||
|
||||
if FileType == '.py':
|
||||
self.PythonToC(InputFile, OutputFile)
|
||||
@@ -638,5 +645,5 @@ class TransPyC:
|
||||
elif FileType == '.c':
|
||||
self.CToPython(InputFile, OutputFile, self.HeaderFiles)
|
||||
else:
|
||||
print(f'Error: Unsupported file type {FileType}')
|
||||
error(f'不支持的文件类型: {FileType}')
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user