Compare commits
3 Commits
06a3dfb205
...
881823fb18
Author | SHA1 | Date | |
---|---|---|---|
881823fb18 | |||
009d296605 | |||
7a3aebf927 |
@ -1,195 +1,198 @@
|
|||||||
from block import *
|
# 优化模块
|
||||||
def is_f(s):
|
# 第一步: 常量传播
|
||||||
return '.' in s or 'e' in s.lower()
|
def constant_propagation(quads):
|
||||||
def tp(sth):
|
#print("Running Constant Propagation")
|
||||||
if sth ==None:
|
value_map = {}
|
||||||
return -1
|
optimized = []
|
||||||
if is_f(sth):
|
|
||||||
return 2
|
|
||||||
if sth[0] >='0' and sth[0] <='9':
|
|
||||||
return 2
|
|
||||||
if sth[0] != '_':
|
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def f(op,a,b):
|
for quad in quads:
|
||||||
if op =='+':
|
op, arg1, arg2, dest = quad
|
||||||
return float(a)+float(b)
|
|
||||||
elif op =='-':
|
|
||||||
return float(a)-float(b)
|
|
||||||
elif op =='*':
|
|
||||||
return float(a)*float(b)
|
|
||||||
elif op =='/':
|
|
||||||
return float(a)/float(b)
|
|
||||||
return 0
|
|
||||||
class DAGNode:
|
|
||||||
cnt = 1
|
|
||||||
def __init__(self,tag=None,l=None,r=None,op=None):
|
|
||||||
self.cnt = DAGNode.cnt
|
|
||||||
DAGNode.cnt += 1
|
|
||||||
self.parents = []
|
|
||||||
self.lc = l
|
|
||||||
self.rc = r
|
|
||||||
self.op = op
|
|
||||||
self.main_tag = tag
|
|
||||||
self.other_tag = set()
|
|
||||||
if tag is not None:
|
|
||||||
self.other_tag.add(tag)
|
|
||||||
def insert(self,tag):
|
|
||||||
self.other_tag.add(tag)
|
|
||||||
if tp(tag) > tp(self.main_tag):
|
|
||||||
self.main_tag = tag
|
|
||||||
def has(self,tag):
|
|
||||||
return tag in self.other_tag
|
|
||||||
class Optimizer:
|
|
||||||
def __init__(self):
|
|
||||||
self.nodes = ["empty"]
|
|
||||||
self.cnt = 0
|
|
||||||
self.abset = dict()
|
|
||||||
self._set = dict()
|
|
||||||
self.ans= []
|
|
||||||
self.cnt_abset = 0
|
|
||||||
def cfind(self,tag):
|
|
||||||
for i in range(1,self.cnt+1)[::-1]:
|
|
||||||
if self.nodes[i].has(tag):
|
|
||||||
return self.nodes[i]
|
|
||||||
self.cnt += 1
|
|
||||||
self.nodes.append(DAGNode(tag=tag))
|
|
||||||
return self.nodes[self.cnt]
|
|
||||||
def cfind_op1(self,op,lc,rc):
|
|
||||||
for i in range(1,self.cnt+1)[::-1]:
|
|
||||||
if self.nodes[i].op==op and ((self.nodes[i].lc == lc and self.nodes[i].rc == rc) or (self.nodes[i].lc == rc and self.nodes[i].rc == lc)):
|
|
||||||
return self.nodes[i]
|
|
||||||
self.cnt +=1
|
|
||||||
self.nodes.append(DAGNode(op=op,l=lc,r=rc))
|
|
||||||
return self.nodes[self.cnt]
|
|
||||||
def cfind_op2(self,op,lc,rc):
|
|
||||||
for i in range(1, self.cnt + 1)[::-1]:
|
|
||||||
if self.nodes[i].op == op and self.nodes[i].lc == lc and self.nodes[i].rc == rc:
|
|
||||||
return self.nodes[i]
|
|
||||||
self.cnt += 1
|
|
||||||
self.nodes.append(DAGNode(op=op, l=lc, r=rc))
|
|
||||||
return self.nodes[self.cnt]
|
|
||||||
def cfindeq(self,tag):
|
|
||||||
for i in range(1,self.cnt+1)[::-1]:
|
|
||||||
if self.nodes[i].has(tag):
|
|
||||||
return [1,self.nodes[i]]
|
|
||||||
self.cnt += 1
|
|
||||||
node = DAGNode()
|
|
||||||
self.nodes.append(node)
|
|
||||||
return [0,node]
|
|
||||||
|
|
||||||
def build(self,lst):
|
if op == '=' and arg1.isdigit():
|
||||||
fg = False
|
# 常量赋值:如 (=, 32, _, _v0)
|
||||||
for _ in lst:
|
value_map[dest] = arg1
|
||||||
if tp(_.d)==1 and self.abset.get(_.d) is None:
|
elif op == '=':
|
||||||
self.abset[_.d] = True
|
# 变量赋值:如 (=, _v0, _, age)
|
||||||
self.cnt_abset += 1
|
if arg1 in value_map:
|
||||||
self.ans = []
|
new_quad = ('=', value_map[arg1], '_', dest)
|
||||||
for _ in lst:
|
optimized.append(new_quad)
|
||||||
op,a,b,res = _.a,_.b,_.c,_.d
|
value_map[dest] = value_map[arg1]
|
||||||
if op =='=':
|
else:
|
||||||
# 将ans插入到a的节点中
|
optimized.append(quad)
|
||||||
num,node = self.cfindeq(a)
|
# 如果 dest 不再被使用,可以考虑删除该赋值
|
||||||
if num == 0:
|
else:
|
||||||
node.main_tag = a
|
# 替换操作数中的变量为已知常量
|
||||||
node.other_tag.add(res)
|
new_arg1 = value_map.get(arg1, arg1)
|
||||||
node.other_tag.add(a)
|
new_arg2 = value_map.get(arg2, arg2) if arg2 != '_' else '_'
|
||||||
else:
|
optimized.append((op, new_arg1, new_arg2, dest))
|
||||||
node.insert(res)
|
|
||||||
if node.op is None:
|
|
||||||
node.op = '='
|
|
||||||
elif op =='+' or op=='*' or op =='==' or op == '!=':
|
|
||||||
# 首先找一下有没有a b节点 , 没有就自己造一个
|
|
||||||
aNode = self.cfind(a)
|
|
||||||
bNode = self.cfind(b)
|
|
||||||
if tp(aNode.main_tag) == tp(bNode.main_tag) and tp(aNode.main_tag) == 2:
|
|
||||||
val = (f(op,aNode.main_tag,bNode.main_tag))
|
|
||||||
if is_f(aNode.main_tag) or is_f(bNode.main_tag):
|
|
||||||
val = str(val)
|
|
||||||
else:
|
|
||||||
val = str(int(val))
|
|
||||||
self.cnt += 1
|
|
||||||
Node = DAGNode(val)
|
|
||||||
Node.insert(res)
|
|
||||||
Node.op = '='
|
|
||||||
self.nodes.append(Node)
|
|
||||||
continue
|
|
||||||
# 然后找一下有没有a op b 的节点 , 有的话插进去
|
|
||||||
# 这里并不能根据a ,b 来查找 , 因为昔人已乘黄鹤去 , 你找到的或许只是曾经的ab
|
|
||||||
|
|
||||||
self.cfind_op1(op,aNode,bNode).insert(res)
|
return optimized
|
||||||
elif op =='-' or op=='%' or op=='/':
|
|
||||||
# 这种不换的元素符
|
|
||||||
aNode = self.cfind(a)
|
|
||||||
bNode = self.cfind(b)
|
|
||||||
if tp(aNode.main_tag) == tp(bNode.main_tag) and tp(aNode.main_tag) == 2:
|
|
||||||
val = (f(op,aNode.main_tag,bNode.main_tag))
|
|
||||||
print(aNode.main_tag,bNode.main_tag)
|
|
||||||
if is_f(aNode.main_tag) or is_f(bNode.main_tag):
|
|
||||||
val = str(val)
|
|
||||||
else:
|
|
||||||
val = str(int(val))
|
|
||||||
self.cnt += 1
|
|
||||||
Node = DAGNode(val)
|
|
||||||
Node.insert(res)
|
|
||||||
Node.op = '='
|
|
||||||
self.nodes.append(Node)
|
|
||||||
continue
|
|
||||||
self.cfind_op2(op,self.cfind(a),self.cfind(b)).insert(res)
|
|
||||||
# 剩下就是while end , if end , el等 , 不用管
|
|
||||||
|
|
||||||
for i in range(1,self.cnt+1)[::-1]:
|
# 第二步: 公共子表达式消除
|
||||||
_ = self.nodes[i]
|
def common_subexpression_elimination(quads):
|
||||||
op = _.op
|
#print("Running Common Subexpression Elimination")
|
||||||
|
expr_map = {}
|
||||||
|
optimized = []
|
||||||
|
temp_counter = 0
|
||||||
|
|
||||||
if op is not None or len(_.other_tag)>1:
|
for quad in quads:
|
||||||
if _.lc is not None and _.rc is not None:
|
op, arg1, arg2, dest = quad
|
||||||
|
|
||||||
if tp(_.main_tag) == 1:
|
if op in ['+', '-', '*', '/']:
|
||||||
if self.abset[_.main_tag] == True:
|
expr_key = f"{arg1} {op} {arg2}"
|
||||||
self.ans.append(FourTuple(op,_.lc.main_tag,_.rc.main_tag,_.main_tag))
|
if expr_key in expr_map:
|
||||||
self.abset[_.main_tag] = False
|
# 复用已有结果
|
||||||
self.cnt_abset -=1
|
reused_var = expr_map[expr_key]
|
||||||
|
optimized.append(('=', reused_var, '_', dest))
|
||||||
|
else:
|
||||||
|
# 新表达式
|
||||||
|
temp_var = f"_t{temp_counter}"
|
||||||
|
temp_counter += 1
|
||||||
|
expr_map[expr_key] = temp_var
|
||||||
|
optimized.append((op, arg1, arg2, temp_var))
|
||||||
|
optimized.append(('=', temp_var, '_', dest))
|
||||||
|
else:
|
||||||
|
optimized.append(quad)
|
||||||
|
|
||||||
if self.cnt_abset == 0:
|
return optimized
|
||||||
fg = True
|
|
||||||
break
|
# 第三步: 死代码消除
|
||||||
else:
|
def dead_code_elimination(quads):
|
||||||
if self._set.get(_.main_tag) is None:
|
#print("Running Dead Code Elimination")
|
||||||
self._set[_.main_tag] = 1
|
used_vars = set()
|
||||||
self.ans.append(FourTuple(op, _.lc.main_tag, _.rc.main_tag, _.main_tag))
|
optimized = []
|
||||||
self.abset[_.main_tag] = False
|
|
||||||
if fg:
|
# 第一遍找出所有被使用的变量
|
||||||
|
for quad in quads:
|
||||||
|
op, arg1, arg2, dest = quad
|
||||||
|
if arg1 != '_' and not arg1.isdigit():
|
||||||
|
used_vars.add(arg1)
|
||||||
|
if arg2 != '_' and not arg2.isdigit():
|
||||||
|
used_vars.add(arg2)
|
||||||
|
|
||||||
|
# 第二遍删除未使用变量的赋值语句
|
||||||
|
for quad in quads:
|
||||||
|
op, arg1, arg2, dest = quad
|
||||||
|
if op == '=' and dest.startswith('_v') and dest not in used_vars:
|
||||||
|
continue # 跳过无用的赋值语句
|
||||||
|
optimized.append(quad)
|
||||||
|
|
||||||
|
return optimized
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 第四步: 控制流优化
|
||||||
|
def control_flow_simplification(quads):
|
||||||
|
# print("Running Control Flow Simplification")
|
||||||
|
optimized = []
|
||||||
|
|
||||||
|
for quad in quads:
|
||||||
|
op, arg1, arg2, dest = quad
|
||||||
|
if op == 'if' and arg2 == 'goto':
|
||||||
|
if arg1.isdigit():
|
||||||
|
if arg1 == '1':
|
||||||
|
optimized.append(('goto', '_', '_', dest))
|
||||||
|
elif arg1 == '0':
|
||||||
|
continue # 恒假,跳过该条件跳转
|
||||||
|
else:
|
||||||
|
optimized.append(quad)
|
||||||
|
else:
|
||||||
|
optimized.append(quad)
|
||||||
|
|
||||||
|
return optimized
|
||||||
|
|
||||||
|
# 第五步: 寄存器重用
|
||||||
|
def register_reuse(quads):
|
||||||
|
#print("Running Register Reuse (Improved)")
|
||||||
|
|
||||||
|
# 计算活跃变量信息
|
||||||
|
live_info = compute_live_vars(quads)
|
||||||
|
|
||||||
|
optimized = []
|
||||||
|
available_temps = [] # 可用于复用的临时变量池
|
||||||
|
|
||||||
|
for i, quad in enumerate(quads):
|
||||||
|
op, arg1, arg2, dest = quad
|
||||||
|
current_live = live_info[i]
|
||||||
|
|
||||||
|
if op == '=':
|
||||||
|
# 查看当前 dest 是否会被后续使用
|
||||||
|
is_dest_used_later = dest in current_live
|
||||||
|
|
||||||
|
# 如果 dest 不再使用,可以加入可用池
|
||||||
|
if not is_dest_used_later and dest.startswith('_'):
|
||||||
|
available_temps.append(dest)
|
||||||
|
|
||||||
|
# 尝试复用已死的临时变量
|
||||||
|
reused = False
|
||||||
|
for var in list(available_temps):
|
||||||
|
if var not in [arg1, arg2] and var not in current_live:
|
||||||
|
# 安全复用
|
||||||
|
optimized.append(('=', arg1, arg2, var))
|
||||||
|
available_temps.remove(var)
|
||||||
|
if var != dest:
|
||||||
|
available_temps.append(dest) # 原 dest 现在可回收
|
||||||
|
reused = True
|
||||||
break
|
break
|
||||||
for __ in _.other_tag:
|
|
||||||
if __ != _.main_tag:
|
|
||||||
if tp(__) == 1:
|
|
||||||
if self.abset[__] == True:
|
|
||||||
|
|
||||||
self.ans.append(FourTuple('=', _.main_tag, '_', __))
|
if not reused:
|
||||||
self.abset[__] = False
|
optimized.append(quad)
|
||||||
self.cnt_abset -= 1
|
if dest.startswith('_') and dest not in current_live:
|
||||||
|
available_temps.append(dest)
|
||||||
|
else:
|
||||||
|
optimized.append(quad)
|
||||||
|
|
||||||
if self.cnt_abset == 0:
|
return optimized
|
||||||
fg = True
|
|
||||||
break
|
def compute_live_vars(quads):
|
||||||
else:
|
"""
|
||||||
if self._set.get(__) == None:
|
活跃变量分析:从后往前推导每个 quad 之后仍会使用的变量
|
||||||
self._set[__] = 1
|
"""
|
||||||
self.ans.append(FourTuple('=',_.main_tag,c='_',d=__))
|
live_vars = set()
|
||||||
if fg:
|
live_info = []
|
||||||
break
|
|
||||||
self.ans = self.ans[::-1]
|
for quad in reversed(quads):
|
||||||
|
op, arg1, arg2, dest = quad
|
||||||
|
|
||||||
|
# 先移除 dest 的影响(因为 dest 被重新定义)
|
||||||
|
if dest in live_vars:
|
||||||
|
live_vars.remove(dest)
|
||||||
|
|
||||||
|
# 如果操作数是变量,则加入活跃集合
|
||||||
|
if arg1 != '_' and not arg1.isdigit():
|
||||||
|
live_vars.add(arg1)
|
||||||
|
if arg2 != '_' and not arg2.isdigit():
|
||||||
|
live_vars.add(arg2)
|
||||||
|
|
||||||
|
# 把当前活跃变量集合复制一份保存下来
|
||||||
|
live_info.append(live_vars.copy())
|
||||||
|
|
||||||
|
# 从后往前遍历,所以需要反转结果
|
||||||
|
live_info.reverse()
|
||||||
|
return live_info
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
# 优化器整合
|
||||||
divider = BlockDivider(l)
|
def optimize(quads):
|
||||||
optimizer = Optimizer()
|
passes = [
|
||||||
ls = divider.run()
|
("Constant Propagation", constant_propagation),
|
||||||
for l in ls:
|
("Common Subexpression Elimination", common_subexpression_elimination),
|
||||||
optimizer.build(l)
|
("Dead Code Elimination", dead_code_elimination),
|
||||||
for i in optimizer.ans:
|
("Control Flow Simplification", control_flow_simplification),
|
||||||
print(i)
|
("Register Reuse", register_reuse),
|
||||||
|
]
|
||||||
|
|
||||||
|
for name, opt_func in passes:
|
||||||
|
# print(f"Running optimization pass: {name}")
|
||||||
|
quads = opt_func(quads)
|
||||||
|
|
||||||
|
return quads
|
||||||
|
|
||||||
|
def output_ir_str(quads):
|
||||||
|
lines = []
|
||||||
|
for i, quad in enumerate(quads):
|
||||||
|
op, arg1, arg2, dest = quad
|
||||||
|
quad = f"({op}, {arg1}, {arg2}, {dest})"
|
||||||
|
lines.append(f"{i} {quad}")
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
l = [
|
|
||||||
'=,1,_,t',
|
|
||||||
|
|
||||||
'=,5,_,t',
|
|
||||||
'=,2,_,_t2',
|
|
||||||
'=,4,_,_t1',
|
|
||||||
'+,4,_t2,_t3',
|
|
||||||
'-,_t2,_t3,_t1',
|
|
||||||
]
|
|
||||||
class FourTuple:
|
|
||||||
cnt =0
|
|
||||||
def __init__(self, a='_',b='_',c='_',d='_'):
|
|
||||||
self.a = a
|
|
||||||
self.b = b
|
|
||||||
self.c = c
|
|
||||||
self.d = d
|
|
||||||
self.cnt = FourTuple.cnt
|
|
||||||
FourTuple.cnt += 1
|
|
||||||
self.block_sign = set(['if','jmp','jmpf','el','ifend','while','fun','return','while','we','goto'])
|
|
||||||
|
|
||||||
|
|
||||||
def is_block_sign(self):
|
|
||||||
return self.a in self.block_sign
|
|
||||||
def __str__(self):
|
|
||||||
return f"({self.a} , {self.b} , {self.c} , {self.d})"
|
|
||||||
class BlockDivider:
|
|
||||||
def __init__(self,lst):
|
|
||||||
self.ans = []
|
|
||||||
self.l =[]
|
|
||||||
for i in lst:
|
|
||||||
k = i.split(',')
|
|
||||||
obj = FourTuple(k[0].strip(),k[1].strip(),k[2].strip(),k[3].strip())
|
|
||||||
self.l.append(obj)
|
|
||||||
# print(obj)
|
|
||||||
def run(self):
|
|
||||||
lst = []
|
|
||||||
for i in self.l:
|
|
||||||
lst.append(i)
|
|
||||||
if i.is_block_sign():
|
|
||||||
self.ans.append(lst)
|
|
||||||
lst = []
|
|
||||||
if lst:
|
|
||||||
self.ans.append(lst)
|
|
||||||
|
|
||||||
return self.ans
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
divider = BlockDivider(l)
|
|
||||||
ans = divider.run()
|
|
||||||
for i in ans:
|
|
||||||
|
|
||||||
for j in i:
|
|
||||||
print(j,end='\t')
|
|
||||||
print()
|
|
10
main.py
10
main.py
@ -5,6 +5,7 @@ from lexical.lexical import Lexical
|
|||||||
from syntax.syntax import Syntax
|
from syntax.syntax import Syntax
|
||||||
from syntax.syntax import LL1Generator
|
from syntax.syntax import LL1Generator
|
||||||
import sys
|
import sys
|
||||||
|
from Optimizer.optimizer import optimize, output_ir_str
|
||||||
|
|
||||||
from semantic.rule import symbol_table_pool
|
from semantic.rule import symbol_table_pool
|
||||||
|
|
||||||
@ -48,6 +49,15 @@ if lexical_success:
|
|||||||
for code in syntax.get_result().root.code:
|
for code in syntax.get_result().root.code:
|
||||||
i += 1
|
i += 1
|
||||||
print(i, ' \t', code)
|
print(i, ' \t', code)
|
||||||
|
|
||||||
|
quads = [tuple(map(str.strip, str(item).strip("()").split(","))) for item in syntax.get_result().root.code]
|
||||||
|
|
||||||
|
optimized_quads = optimize(quads)
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(f"优化后的四元式:\t")
|
||||||
|
print(output_ir_str(optimized_quads))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print('错误原因:\t', syntax.get_error().info)
|
print('错误原因:\t', syntax.get_error().info)
|
||||||
else:
|
else:
|
||||||
|
2
test4.hy
2
test4.hy
@ -1,7 +1,7 @@
|
|||||||
// test4:嵌套 if 判断(复杂控制流)
|
// test4:嵌套 if 判断(复杂控制流)
|
||||||
|
|
||||||
fn max(x: i32, y: i32) -> i32 {
|
fn max(x: i32, y: i32) -> i32 {
|
||||||
if x > y {
|
if x >= y {
|
||||||
return x;
|
return x;
|
||||||
} else {
|
} else {
|
||||||
return y;
|
return y;
|
||||||
|
28
tk_ui.py
28
tk_ui.py
@ -4,6 +4,7 @@ from lexical.lexical import Lexical
|
|||||||
from syntax.syntax import Syntax
|
from syntax.syntax import Syntax
|
||||||
from semantic.rule import symbol_table_pool
|
from semantic.rule import symbol_table_pool
|
||||||
from syntax.syntax import LL1Generator
|
from syntax.syntax import LL1Generator
|
||||||
|
from Optimizer.optimizer import optimize, output_ir_str
|
||||||
|
|
||||||
def process_code(input_code):
|
def process_code(input_code):
|
||||||
lexical = Lexical()
|
lexical = Lexical()
|
||||||
@ -30,6 +31,14 @@ def process_code(input_code):
|
|||||||
for code in syntax.get_result().root.code:
|
for code in syntax.get_result().root.code:
|
||||||
i += 1
|
i += 1
|
||||||
output.append(f"{i} \t{code}")
|
output.append(f"{i} \t{code}")
|
||||||
|
|
||||||
|
quads = [tuple(map(str.strip, str(item).strip("()").split(","))) for item in syntax.get_result().root.code]
|
||||||
|
|
||||||
|
optimized_quads = optimize(quads)
|
||||||
|
|
||||||
|
output.append('\n')
|
||||||
|
output.append(f"优化后的四元式:\t")
|
||||||
|
output.append(output_ir_str(optimized_quads))
|
||||||
return '\n'.join(output), ''
|
return '\n'.join(output), ''
|
||||||
else:
|
else:
|
||||||
return '\n'.join(output), '错误原因:\t' + syntax.get_error().info
|
return '\n'.join(output), '错误原因:\t' + syntax.get_error().info
|
||||||
@ -56,12 +65,27 @@ root.title("Hydrogen语言编译器前端演示")
|
|||||||
input_text = scrolledtext.ScrolledText(root, width=80, height=20)
|
input_text = scrolledtext.ScrolledText(root, width=80, height=20)
|
||||||
input_text.pack(padx=10, pady=5)
|
input_text.pack(padx=10, pady=5)
|
||||||
|
|
||||||
# 提交按钮
|
# 提交按钮和清空按钮在同一行
|
||||||
|
button_frame = tk.Frame(root)
|
||||||
|
def on_generate_ll1_table():
|
||||||
|
try:
|
||||||
|
obj = LL1Generator()
|
||||||
|
obj.compile()
|
||||||
|
obj.show_me_what_you_got("LL1_table.csv")
|
||||||
|
messagebox.showinfo("提示", "成功生成预测表")
|
||||||
|
except Exception as e:
|
||||||
|
messagebox.showerror("生成预测表异常", str(e))
|
||||||
|
|
||||||
|
submit_btn = tk.Button(button_frame, text="生成产生式的预测表", command=on_generate_ll1_table)
|
||||||
|
|
||||||
|
submit_btn.pack(side=tk.LEFT, padx=5)
|
||||||
|
|
||||||
|
button_frame.pack(pady=5)
|
||||||
submit_btn = tk.Button(root, text="提交", command=on_submit)
|
submit_btn = tk.Button(root, text="提交", command=on_submit)
|
||||||
submit_btn.pack(pady=5)
|
submit_btn.pack(pady=5)
|
||||||
|
|
||||||
# 输出框
|
# 输出框
|
||||||
output_text = scrolledtext.ScrolledText(root, width=80, height=20, bg="#ffffff")
|
output_text = scrolledtext.ScrolledText(root, width=80, height=20, bg="#000000")
|
||||||
output_text.pack(padx=10, pady=5)
|
output_text.pack(padx=10, pady=5)
|
||||||
|
|
||||||
# 错误信息框
|
# 错误信息框
|
||||||
|
Loading…
Reference in New Issue
Block a user