Update scl.py

这个提交包含在:
2026-04-09 13:14:20 +08:00
提交者 GitHub
父节点 caada4dd0c
当前提交 71ba30e555
+169 -171
查看文件
@@ -12,13 +12,62 @@ import tkinter as tk
class SCLInterpreter: class SCLInterpreter:
def __init__(self): def __init__(self):
self.variables = {} self.variables = {} # 变量存储
self.functions = {} self.functions = {} # 函数存储
self.plugins = {} self.plugins = {} # 插件存储
self.loaded_plugins = set() self.loaded_plugins = set() # 已加载插件
self.debug_mode = False # 默认为false,不开启debug模式 self.debug_mode = False # 默认为false,不开启debug模式
# 缓存管理 - 限制缓存大小
self.expression_cache = {} # 缓存表达式求值结果 self.expression_cache = {} # 缓存表达式求值结果
self.token_cache = {} # 缓存tokenize结果 self.token_cache = {} # 缓存tokenize结果
self.code_block_cache = {} # 缓存代码块执行结果
self.statement_cache = {} # 缓存语句解析结果
# 缓存大小限制
self.MAX_CACHE_SIZE = 1000
# 预编译正则表达式
import re
self.comment_pattern = re.compile(r'^\s*(#|//)')
self.empty_pattern = re.compile(r'^\s*$')
# 预定义常量
self.multi_line_starts = {
'sif ', 'swhile :', 'swhile |', 'swhi ', 'srg', 'sdef <', 'sclass <'
}
# 操作符优先级映射
self.operator_precedence = {
'*': 3,
'/': 3,
'+': 2,
'-': 2,
'>': 1,
'<': 1,
'==': 1,
'!=': 1,
'>=': 1,
'<=': 1,
'&': 0,
'|': 0
}
# 快速操作映射
self.operation_map = {
'+': lambda a, b: str(a) + str(b) if isinstance(a, str) or isinstance(b, str) else a + b,
'-': lambda a, b: a - b,
'*': lambda a, b: a * b,
'/': lambda a, b: a / b if b != 0 else 0,
'>': lambda a, b: a > b,
'<': lambda a, b: a < b,
'==': lambda a, b: a == b,
'!=': lambda a, b: a != b,
'>=': lambda a, b: a >= b,
'<=': lambda a, b: a <= b,
'&': lambda a, b: a and b,
'|': lambda a, b: a or b
}
def _find_plugin_class(self, plugin_module): def _find_plugin_class(self, plugin_module):
"""Find the plugin class in a module""" """Find the plugin class in a module"""
@@ -26,6 +75,13 @@ class SCLInterpreter:
if name.endswith('Plugin') and name[0].isupper(): if name.endswith('Plugin') and name[0].isupper():
return name return name
return None return None
def _manage_cache(self, cache):
"""管理缓存大小,防止内存过度使用"""
if len(cache) > self.MAX_CACHE_SIZE:
# 删除最旧的缓存项
for key in list(cache.keys())[:len(cache) - self.MAX_CACHE_SIZE]:
del cache[key]
def _register_plugin_instance(self, plugin_name, plugin_instance, is_web=False, url=None): def _register_plugin_instance(self, plugin_name, plugin_instance, is_web=False, url=None):
"""Register a plugin instance""" """Register a plugin instance"""
@@ -184,6 +240,9 @@ class SCLInterpreter:
code = code.strip() code = code.strip()
i = 0 i = 0
n = len(code) n = len(code)
if n == 0:
self.token_cache[code_hash] = []
return []
# 预定义常量 # 预定义常量
whitespace_chars = {' ', '\t', '\n', '\r'} whitespace_chars = {' ', '\t', '\n', '\r'}
@@ -191,7 +250,7 @@ class SCLInterpreter:
paren_chars = {'(', ')', '[', ']', '{', '}'} paren_chars = {'(', ')', '[', ']', '{', '}'}
# 预分配空间,减少列表扩展开销 # 预分配空间,减少列表扩展开销
tokens = [None] * (n // 2) # 预估令牌数量 tokens = []
token_count = 0 token_count = 0
while i < n: while i < n:
@@ -207,23 +266,18 @@ class SCLInterpreter:
if char == '"': if char == '"':
# 字符串处理 # 字符串处理
j = i + 1 j = i + 1
string_content = [] # 快速查找字符串结束位置
while j < n and code[j] != '"': while j < n:
if code[j] == '\\' and j + 1 < n: if code[j] == '\\' and j + 1 < n:
j += 1 j += 2
if code[j] == 'n': elif code[j] == '"':
string_content.append('\n') break
elif code[j] == '\\':
string_content.append('\\')
else:
string_content.append(code[j])
else: else:
string_content.append(code[j]) j += 1
j += 1 # 处理转义字符
if token_count >= len(tokens): string_content = code[i+1:j]
tokens.extend([None] * (n // 2)) string_content = string_content.replace('\\n', '\n').replace('\\\\', '\\')
tokens[token_count] = ('STRING', ''.join(string_content)) tokens.append(('STRING', string_content))
token_count += 1
i = j + 1 if j < n else n i = j + 1 if j < n else n
elif char.isdigit(): elif char.isdigit():
@@ -231,10 +285,7 @@ class SCLInterpreter:
j = i j = i
while j < n and (code[j].isdigit() or code[j] == '.'): while j < n and (code[j].isdigit() or code[j] == '.'):
j += 1 j += 1
if token_count >= len(tokens): tokens.append(('NUMBER', code[i:j]))
tokens.extend([None] * (n // 2))
tokens[token_count] = ('NUMBER', code[i:j])
token_count += 1
i = j i = j
elif char.isalpha() or char == '_': elif char.isalpha() or char == '_':
@@ -242,24 +293,15 @@ class SCLInterpreter:
j = i j = i
while j < n and (code[j].isalnum() or code[j] == '_'): while j < n and (code[j].isalnum() or code[j] == '_'):
j += 1 j += 1
if token_count >= len(tokens): tokens.append(('IDENTIFIER', code[i:j]))
tokens.extend([None] * (n // 2))
tokens[token_count] = ('IDENTIFIER', code[i:j])
token_count += 1
i = j i = j
elif char == '|': elif char == '|':
if token_count >= len(tokens): tokens.append(('SEPARATOR', char))
tokens.extend([None] * (n // 2))
tokens[token_count] = ('SEPARATOR', char)
token_count += 1
i += 1 i += 1
elif char == ':': elif char == ':':
if token_count >= len(tokens): tokens.append(('ASSIGN', char))
tokens.extend([None] * (n // 2))
tokens[token_count] = ('ASSIGN', char)
token_count += 1
i += 1 i += 1
elif char in operator_chars: elif char in operator_chars:
@@ -267,93 +309,73 @@ class SCLInterpreter:
j = i j = i
while j < n and code[j] in operator_chars: while j < n and code[j] in operator_chars:
j += 1 j += 1
if token_count >= len(tokens): tokens.append(('OPERATOR', code[i:j]))
tokens.extend([None] * (n // 2))
tokens[token_count] = ('OPERATOR', code[i:j])
token_count += 1
i = j i = j
elif char in paren_chars: elif char in paren_chars:
if token_count >= len(tokens): tokens.append(('PAREN', char))
tokens.extend([None] * (n // 2))
tokens[token_count] = ('PAREN', char)
token_count += 1
i += 1 i += 1
elif char == '#': elif char == '#' or (char == '/' and i + 1 < n and code[i + 1] == '/'):
# 注释处理 # 注释处理
j = i j = i
while j < n and code[j] != '\n': while j < n and code[j] != '\n':
j += 1 j += 1
if token_count >= len(tokens):
tokens.extend([None] * (n // 2))
tokens[token_count] = ('COMMENT', code[i:j])
token_count += 1
i = j
elif char == '/' and i + 1 < n and code[i + 1] == '/':
# 注释处理
j = i
while j < n and code[j] != '\n':
j += 1
if token_count >= len(tokens):
tokens.extend([None] * (n // 2))
tokens[token_count] = ('COMMENT', code[i:j])
token_count += 1
i = j i = j
else: else:
if token_count >= len(tokens): tokens.append(('UNKNOWN', char))
tokens.extend([None] * (n // 2))
tokens[token_count] = ('UNKNOWN', char)
token_count += 1
i += 1 i += 1
# 截断到实际使用的长度
result = tokens[:token_count]
# 缓存结果 # 缓存结果
self.token_cache[code_hash] = result self.token_cache[code_hash] = tokens
# 管理缓存大小
self._manage_cache(self.token_cache)
return result return tokens
def parse_expression(self, tokens, pos): def parse_expression(self, tokens, pos):
"""Parse an expression from the tokens (optimized with precedence handling)""" """Parse an expression from the tokens (optimized with precedence handling)"""
# 简单表达式解析器,支持二元运算 # 检查缓存
cache_key = (tuple(tokens), pos)
if cache_key in self.statement_cache:
return self.statement_cache[cache_key]
if pos >= len(tokens): if pos >= len(tokens):
return None, pos result = (None, pos)
self.statement_cache[cache_key] = result
return result
# 解析左操作数 # 递归下降解析器,支持运算符优先级
left, pos = self.parse_primary(tokens, pos) def parse_level(level, pos):
if left is None: if level == 4: # 最高优先级:括号和基本表达式
return None, pos return self.parse_primary(tokens, pos)
# 解析运算符和右操作数
# 优先级: * / > + -
while pos < len(tokens) and tokens[pos][0] == 'OPERATOR':
op = tokens[pos][1]
if op not in '+-*/':
break
# 处理优先级 left, pos = parse_level(level + 1, pos)
if op in '*/': if left is None:
# 高优先级,直接解析右操作数 return None, pos
while pos < len(tokens) and tokens[pos][0] == 'OPERATOR':
op = tokens[pos][1]
op_prec = self.operator_precedence.get(op, -1)
if op_prec != level:
break
pos += 1 pos += 1
right, pos = self.parse_primary(tokens, pos) right, pos = parse_level(level + 1, pos)
if right is None:
return None, pos
# 构建二元表达式
left = [left, tokens[pos-1], right]
else: # op in '+-'
# 低优先级,检查下一个运算符
pos += 1
right, pos = self.parse_primary(tokens, pos)
if right is None: if right is None:
return None, pos return None, pos
# 构建二元表达式 # 构建二元表达式
left = [left, tokens[pos-1], right] left = [left, tokens[pos-1], right]
return left, pos
return left, pos # 从最低优先级开始解析
result = parse_level(0, pos)
self.statement_cache[cache_key] = result
return result
def parse_primary(self, tokens, pos): def parse_primary(self, tokens, pos):
"""Parse a primary expression""" """Parse a primary expression"""
@@ -665,26 +687,21 @@ class SCLInterpreter:
result = 0 result = 0
if isinstance(expr, list): if isinstance(expr, list):
if len(expr) == 3 and expr[1][0] == 'OPERATOR': if len(expr) == 3 and expr[1][0] == 'OPERATOR':
# 递归评估左右操作数
left = self.evaluate_expression(expr[0]) left = self.evaluate_expression(expr[0])
op = expr[1][1] op = expr[1][1]
right = self.evaluate_expression(expr[2]) right = self.evaluate_expression(expr[2])
# 使用预定义的操作映射 # 使用快速操作映射
if op == '+': if op in self.operation_map:
result = str(left) + str(right) if isinstance(left, str) or isinstance(right, str) else left + right result = self.operation_map[op](left, right)
elif op == '-':
result = left - right
elif op == '*':
result = left * right
elif op == '/':
result = left / right if right != 0 else 0
elif expr[0] == 'STRING': elif expr[0] == 'STRING':
result = expr[1] result = expr[1]
elif expr[0] == 'NUMBER': elif expr[0] == 'NUMBER':
# 缓存数字转换结果 # 快速数字转换
num_str = expr[1]
try: try:
num_str = expr[1]
if '.' in num_str: if '.' in num_str:
result = float(num_str) result = float(num_str)
else: else:
@@ -700,19 +717,23 @@ class SCLInterpreter:
args = expr[2] args = expr[2]
# 评估参数 # 评估参数
evaluated_args = [self.evaluate_expression(arg) for arg in args] evaluated_args = []
for arg in args:
evaluated_args.append(self.evaluate_expression(arg))
# 检查是否有插件处理函数调用 # 快速插件查找
for plugin in self.plugins.values(): for plugin in self.plugins.values():
plugin_result = plugin.execute_statement(('FUNCTION_CALL', func_name, evaluated_args)) if hasattr(plugin, 'execute_statement'):
# 检查结果是否不是布尔值 - 这意味着函数返回了一个值 plugin_result = plugin.execute_statement(('FUNCTION_CALL', func_name, evaluated_args))
if not isinstance(plugin_result, bool): # 检查结果是否不是布尔值 - 这意味着函数返回了一个值
result = plugin_result if not isinstance(plugin_result, bool):
break result = plugin_result
break
# 缓存结果 # 缓存结果
if not isinstance(expr, list) or (len(expr) == 3 and expr[1][0] == 'OPERATOR'): self.expression_cache[expr_key] = result
self.expression_cache[expr_key] = result # 管理缓存大小
self._manage_cache(self.expression_cache)
return result return result
@@ -880,59 +901,49 @@ class SCLInterpreter:
"""Execute the given SCL code (optimized with caching and efficient processing)""" """Execute the given SCL code (optimized with caching and efficient processing)"""
# 检查缓存 # 检查缓存
code_hash = hash(code) code_hash = hash(code)
if code_hash in self.token_cache: if code_hash in self.code_block_cache:
# 直接使用缓存的token结果 return self.code_block_cache[code_hash]
pass
def smart_split(code): def smart_split(code):
"""Optimized line splitting that handles strings correctly""" """Optimized line splitting that handles strings correctly"""
# 快速处理
code_len = len(code)
if code_len == 0:
return []
# 预分配空间
lines = [] lines = []
current_line = [] current_line = []
in_string = False in_string = False
# 预分配空间,减少列表扩展开销
code_len = len(code)
current_line = [''] * code_len
line_pos = 0
for char in code: for char in code:
if char == '"': if char == '"':
in_string = not in_string in_string = not in_string
current_line[line_pos] = char current_line.append(char)
line_pos += 1
elif char == '\n' and not in_string: elif char == '\n' and not in_string:
lines.append(''.join(current_line[:line_pos])) lines.append(''.join(current_line))
current_line = [''] * code_len current_line = []
line_pos = 0
else: else:
current_line[line_pos] = char current_line.append(char)
line_pos += 1
if line_pos > 0: if current_line:
lines.append(''.join(current_line[:line_pos])) lines.append(''.join(current_line))
return lines return lines
lines = smart_split(code) lines = smart_split(code)
if not lines:
self.code_block_cache[code_hash] = True
return True
# 用于处理多行语句 # 用于处理多行语句
multi_line_buffer = [] multi_line_buffer = []
in_multi_line = False in_multi_line = False
nested_level = 0 # 用于跟踪嵌套级别 nested_level = 0 # 用于跟踪嵌套级别
# 预定义常量(使用集合提高查找速度)
multi_line_starts = {
'sif ', 'swhile :', 'swhile |', 'swhi ', 'srg', 'sdef <', 'sclass <'
}
# 预编译正则表达式,用于快速检查注释和空行
import re
comment_pattern = re.compile(r'^\s*(#|//)')
empty_pattern = re.compile(r'^\s*$')
for line_num, line in enumerate(lines, 1): for line_num, line in enumerate(lines, 1):
# 快速跳过空行和注释 # 快速跳过空行和注释
if empty_pattern.match(line) or comment_pattern.match(line): if self.empty_pattern.match(line) or self.comment_pattern.match(line):
continue continue
# 处理插件导入和SCL文件导入 # 处理插件导入和SCL文件导入
@@ -943,19 +954,21 @@ class SCLInterpreter:
if import_content.startswith('scl :'): if import_content.startswith('scl :'):
scl_path = import_content[5:].strip() scl_path = import_content[5:].strip()
if not self.import_scl_file(scl_path, line_num): if not self.import_scl_file(scl_path, line_num):
self.code_block_cache[code_hash] = False
return False return False
else: else:
# 插件导入 # 插件导入
if not self.load_plugin(import_content): if not self.load_plugin(import_content):
print(f"Error at line {line_num}: Failed to load plugin {import_content}") print(f"Error at line {line_num}: Failed to load plugin {import_content}")
print(f"Code: {line}") print(f"Code: {line}")
self.code_block_cache[code_hash] = False
return False return False
continue continue
try: try:
# 检查是否是多行语句的开始 # 检查是否是多行语句的开始
is_multi_line_start = False is_multi_line_start = False
for prefix in multi_line_starts: for prefix in self.multi_line_starts:
if line.startswith(prefix): if line.startswith(prefix):
is_multi_line_start = True is_multi_line_start = True
break break
@@ -965,60 +978,36 @@ class SCLInterpreter:
is_multi_line_start = True is_multi_line_start = True
if is_multi_line_start: if is_multi_line_start:
# 打印调试信息
if self.debug_mode:
print(f"Debug: Found multi-line statement start: {line}")
multi_line_buffer.append(line) multi_line_buffer.append(line)
if not in_multi_line: if not in_multi_line:
in_multi_line = True in_multi_line = True
nested_level = 1 # 开始一个新的多行语句,嵌套级别为1 nested_level = 1 # 开始一个新的多行语句,嵌套级别为1
# 打印调试信息
if self.debug_mode:
print(f"Debug: Started new multi-line statement, nested_level = {nested_level}")
else: else:
nested_level += 1 # 遇到新的嵌套语句,嵌套级别加1 nested_level += 1 # 遇到新的嵌套语句,嵌套级别加1
# 打印调试信息
if self.debug_mode:
print(f"Debug: Found nested statement, nested_level = {nested_level}")
# 检查是否是多行语句的结束 # 检查是否是多行语句的结束
elif line == 'end' and in_multi_line: elif line == 'end' and in_multi_line:
# 打印调试信息
if self.debug_mode:
print(f"Debug: Found multi-line statement end: {line}")
multi_line_buffer.append(line) multi_line_buffer.append(line)
nested_level -= 1 # 遇到end,嵌套级别减1 nested_level -= 1 # 遇到end,嵌套级别减1
# 打印调试信息
if self.debug_mode:
print(f"Debug: Decreased nested_level to {nested_level}")
if nested_level == 0: if nested_level == 0:
# 嵌套级别为0,说明是外部语句的结束 # 嵌套级别为0,说明是外部语句的结束
in_multi_line = False in_multi_line = False
# 处理完整的多行语句 # 处理完整的多行语句
multi_line_code = '\n'.join(multi_line_buffer) multi_line_code = '\n'.join(multi_line_buffer)
multi_line_buffer = [] multi_line_buffer = []
# 打印调试信息 # 处理多行语句
if self.debug_mode:
print(f"Debug: Processing complete multi-line statement:\n{multi_line_code}")
# 这里我们需要特殊处理多行语句
# 简单起见,我们将多行语句作为一个整体进行tokenize和parse
# 注意:这种方法可能不是最优的,但是可以解决当前的问题
tokens = self.tokenize(multi_line_code) tokens = self.tokenize(multi_line_code)
# 打印调试信息
if self.debug_mode:
print(f"Debug: Tokens: {tokens}")
if tokens: if tokens:
stmt, _ = self.parse_statement(tokens, 0) stmt, _ = self.parse_statement(tokens, 0)
# 打印调试信息
if self.debug_mode:
print(f"Debug: Parsed statement: {stmt}")
if stmt: if stmt:
if not self.execute_statement(stmt): if not self.execute_statement(stmt):
print(f"Error at line {line_num}: Failed to execute statement") print(f"Error at line {line_num}: Failed to execute statement")
print(f"Code: {multi_line_code}") print(f"Code: {multi_line_code}")
self.code_block_cache[code_hash] = False
return False return False
else: else:
print(f"Error at line {line_num}: Invalid syntax") print(f"Error at line {line_num}: Invalid syntax")
print(f"Code: {multi_line_code}") print(f"Code: {multi_line_code}")
self.code_block_cache[code_hash] = False
return False return False
# 处理多行语句的中间部分 # 处理多行语句的中间部分
elif in_multi_line: elif in_multi_line:
@@ -1036,24 +1025,33 @@ class SCLInterpreter:
if not self.execute_statement(stmt): if not self.execute_statement(stmt):
print(f"Error at line {line_num}: Failed to execute statement") print(f"Error at line {line_num}: Failed to execute statement")
print(f"Code: {line}") print(f"Code: {line}")
self.code_block_cache[code_hash] = False
return False return False
else: else:
print(f"Error at line {line_num}: Invalid syntax") print(f"Error at line {line_num}: Invalid syntax")
print(f"Code: {line}") print(f"Code: {line}")
self.code_block_cache[code_hash] = False
return False return False
except Exception as e: except Exception as e:
print(f"Error at line {line_num}: {e}") print(f"Error at line {line_num}: {e}")
print(f"Code: {line}") print(f"Code: {line}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
self.code_block_cache[code_hash] = False
return False return False
# 检查是否有未完成的多行语句 # 检查是否有未完成的多行语句
if in_multi_line: if in_multi_line:
print(f"Error at line {line_num}: Unclosed multi-line statement") print(f"Error at line {line_num}: Unclosed multi-line statement")
print(f"Code: {''.join(multi_line_buffer)}") print(f"Code: {''.join(multi_line_buffer)}")
self.code_block_cache[code_hash] = False
return False return False
# 缓存结果
self.code_block_cache[code_hash] = True
# 管理缓存大小
self._manage_cache(self.code_block_cache)
return True return True
def nano_editor(file_path=None): def nano_editor(file_path=None):