Merge remote-tracking branch 'origin/main'

This commit is contained in:
Guan Inf 2025-06-12 15:13:03 +08:00
commit eef872c3f8
26 changed files with 554 additions and 2766 deletions

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 John Kindem
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.

219
README.md
View File

@ -1,23 +1,208 @@
# C(缩减版)语言编译器前端
## 是什么
NUAA 2017年编译原理课设词法分析使用正则表达式语法分析使用LL(1)文法分析器,
语义分析使用自上而下翻译,使用 Python 语言编写,面向配置化,稍加改造可以适用其他文法
<h1 align="center"> Hydrogen 语言大纲</h1>
## 怎么使用
[toc]
## 1. 语法文档
### 1.1 变量
变量声明
```go
i32 f1; // 整型字变量默认为i32,支持自动类型转换
f32 f2;
i32[5] f3; // 数组声明
f32[93] f4;
```
git clone https://github.com/FlyAndNotDown/CSub-CompilerFrontend.git
#### 支持的数值类型
| 实数类型 | 数组类型 |
| -------- | ------------ |
| i32 | i32[num-int] |
| f32 | f32[num-int] |
### 1.2 注释
#### 单行注释
单行注释使用 `//` 开头,后面跟随注释内容。例如:
```
// 这是一个单行注释
```
在 PyCharm 中打开新建项目导入代码即可Python 使用版本为 3 以上,请不要使用 Python2 运行该项目
## 代码结构说明
* main.py 编译器主程序
* error.py 存放错误相关的类和代码
* test.c 要编译的文件
* lexical 词法分析
* syntax 语法分析
* semantic 语义分析
#### 多行注释
另外,三大分析中 rule.py 即是支持编译器的所有文法、词法、语义规则,加以改动即可面向一些其他的文法和语言使用
多行注释使用 `/*` 开头,并以 `*/` 结束。例如:
## 关于
NUAA 161520311 John Kindem
```
/*
这是一个多行注释
可以跨越多行
*/
```
### 1.3 控制结构
#### if 语法
```
if condition {
// 当 condition 为 true 时执行的代码
} else {
// 当 condition 为 false 时执行的代码
}
```
condition 的类型必须是 bool
可以使用 else 语法来检查多个条件,示例:
```
fn main() {
i32 type;
i32 foo;
age = 32;
if foo >= 60 {
a = 0;
} else {
if foo >= 18 {
a = 1;
} else {
a = 2;
}
}
}
```
#### While 语法
`while` 语句用于循环执行代码块。Nature 语言中的 `for` 语句有三种主要形式:经典循环、条件循环。
- **经典循环**
经典循环用于执行固定次数的循环。基本语法如下:
```
fn main() {
i32 a;
i32 sum;
a = 0;
sum = 0;
while a <= 100 {
sum = sum + a;
a = a + 1;
}
}
```
在这个示例中,循环从 `i = 1` 开始,每次循环 `i` 增加 1直到 `i` 大于 100。
- 1.5 算术运算符
| 优先级 | 关键字 | 使用示例 | 说明 |
| ------ | ------ | -------------- | ---------------------- |
| 1 | () | (1 + 1) | (expr) |
| 2 | / | 1 / 2 | 除 |
| 2 | * | 1 * 2 | 乘 |
| 2 | % | 5 % 2 | 余数 |
| 3 | + | 1 + 1 | 加 |
| 3 | - | 1 - 1 | 减 |
| 4 | > | 1 > 2 | 大于 |
| 4 | >= | 1 >= 2 | 大于等于 |
| 4 | < | 1 < 2 | 小于 |
| 4 | <= | 1 <= 2 | 小于等于 |
| 4 | == | 1 == 2 | 等于 |
| 4 | != | 1 != 2 | 不等于 |
### 1.4 函数
函数声明语法如下
````
fn 函数名(参数名:参数类型,....) -> 返回类型 {
...
}
````
> 注意: -> 返回类型可以省略省略后默认返回void
>
> 例子:
```
fn main() {
return 0;
}
```
## 2. 实现细节
### 2.1 符号表
#### 全局变量表
| Name | Type | Width | Offset |
| ---- | ---- | ----- | ------ |
| g_a | i32 | 4 | 0 |
| | | | |
#### 函数表
| Function Name | Return Type | Local Var Table |
| ------------- | ----------- | --------------- |
| main | void | main |
#### 局部变量表
表名称main
| Name | Type | Width | Offset | Is Param |
| ---- | ----- | ----- | ------ | -------- |
| test | i32 | 4 | 0 | True |
| a | i32[] | 128 | 4 | False |
| | | | | |
| | | | | |
### 2.2 四元式
1. **函数定义**
- 表示函数入口,例如:(fun, _, _, main)(定义主函数)。
2. **赋值操作**
- 将常量或变量赋给临时变量或目标变量,例如:
- (=, 32, _, _v0)(常量赋值)
- (=, _v0, _, age)(变量赋值)
- (=, 0, _, _v18)(常量赋值给临时变量)。
3. **比较操作**
- 包括大于等于 (>=) 和小于等于 (<=),生成布尔结果,例如:
- (>=, foo, _v1, _v2)
- (<=, foo, _v10, _v11)
4. **条件跳转**
- 根据条件判断跳转到指定基本块,例如:(if, _v3, goto, __b3)。
5. **无条件跳转**
- 直接跳转到指定基本块,例如:(goto, _, _, __b5)。
6. **基本块标记**
- 定义控制流中的基本块,例如:(block, _, _, __b3)。
7. **算术操作**
- 执行加法运算,例如:(+, age, a, _v13)。
8. **返回操作**
- **新增**:表示函数返回特定值,例如:(return, _, _, _v18)(返回临时变量 _v18 的值)。

View File

@ -13,10 +13,11 @@ token_type = [
'fn',
'multiplication',
'division',
'bigger',
'yushu',
'bigger-equal',
'smaller',
'smaller-equal',
'bigger',
'smaller',
'equal',
'not-equal',
'evaluate',
@ -66,6 +67,7 @@ regex_dict = {
'subtraction': r'-',
'multiplication': r'\*',
'division': r'/',
'yushu': r'%',
'bigger': r'>',
'bigger-equal': r'>=',
'smaller': r'<',
@ -82,7 +84,7 @@ regex_dict = {
'right-bracket': r'\]',
'left-brace': r'\{',
'right-brace': r'\}',
'id': r'[a-zA-Z][a-zA-Z]*',
'id': r'[a-zA-Z][a-zA-Z_]*',
'float-num': r'\d+\.\d+[eE][+-]\d+|\d+\.\d+|\d+[eE][+-]\d+',
'int-num': r'[1-9][0-9]*|0',
}

View File

@ -4,6 +4,7 @@
from lexical.lexical import Lexical
from syntax.syntax import Syntax
from syntax.syntax import LL1Generator
import sys
# print(PredictingAnalysisTable().compile())
@ -13,8 +14,12 @@ from syntax.syntax import LL1Generator
# 新建词法分析器
lexical = Lexical()
if len(sys.argv) < 2:
print("请提供源代码文件名作为参数。")
sys.exit(1)
source_filename = sys.argv[1]
# 载入源代码
lexical.load_source(open('test9.c', encoding='utf-8', errors='ignore').read())
lexical.load_source(open(source_filename, encoding='utf-8', errors='ignore').read())
# 执行词法分析
lexical_success = lexical.execute()
# 打印结果
@ -35,7 +40,7 @@ if lexical_success:
if syntax_success:
print()
print('语义分析结果:\t')
print('三地址代码:\t')
print('四元式代码:\t')
i = -1
for code in syntax.get_result().root.code:
i += 1

View File

@ -1,488 +0,0 @@
class Sign:
"""
符号
"""
def __init__(self, sign_type, sign_str='', sign_line=-1):
"""
构造
:param sign_type: 符号的类型
:param sign_str: 符号的内容(可以为空)
:param sign_line: 符号所在行数(可以为空)
"""
self.type = sign_type
self.str = sign_str
self.line = sign_line
def is_terminal_sign(self):
"""
是不是终结符
:return: True/False
"""
if self.type == 'empty':
return True
else:
for i in terminal_sign_type:
if i == self.type:
return True
return False
def is_non_terminal_sign(self):
"""
是不是非终结符
:return: True/False
"""
for i in non_terminal_sign_type:
if i == self.type:
return True
return False
def is_empty_sign(self):
"""
是不是空字
:return: True/False
"""
return self.type == 'empty'
class Production:
"""
产生式
"""
def __init__(self, left_type, right_types, semantic_start, semantic_children, semantic_end):
"""
产生式左边
:param left_type: 产生式左边的符号类型
:param right_types: 产生式右边的符号类型列表
:param semantic_start: 语义操作关键字 - 开始
:param semantic_children: 语义操作关键字 - 孩子
:param semantic_end: 语义操作关键字 - 结束
"""
self.left = Sign(left_type)
self.right = list()
for i in right_types:
self.right.append(Sign(i))
# 调试用的
self.str = self.left.type + ' ->'
for i in self.right:
self.str += ' ' + i.type
# 语义操作关键字
self.semantic_start = semantic_start
self.semantic_children = list()
for c in semantic_children:
self.semantic_children.append(c)
self.semantic_end = semantic_end
"""
1. program -> define-list
2. define-list -> define define-list
| empty
3. define -> type ID define-type
4. define-type -> var-define-follow
| fun-define-follow
5. var-define-follow -> ;
| [ NUM ] ;
6. type -> int
| void
7. fun-define-follow -> ( params ) code-block
8. params -> param-list
| empty
9. param-list -> param param-follow
10. param-follow -> , param param-follow
| empty
11. param -> type ID array-subscript
12. array-subscript -> [ ]
| empty
13. code-block -> { local-define-list code-list }
14. local-define-list -> local-var-define local-define-list
| empty
15. local-var-define -> type ID var-define-follow
16. code-list -> code code-list
| empty
17. code -> normal-statement
| selection-statement
| iteration-statement
| return-statement
18. normal-statement -> ;
| ID normal-statement-follow
19. normal-statement-follow -> var-follow = expression ;
| call-follow ;
20. call-follow -> ( call-params )
21. call-params -> call-param-list
| empty
22. call-param-list -> expression call-param-follow
23. call-param-follow -> , expression call-param-follow
| empty
24. selection-statement -> if ( expression ) { code-list } selection-follow
25. selection-follow -> else { code-list }
| empty
26. iteration-statement -> while ( expression ) iteration-follow
27. iteration-follow -> { code-list }
| code
28. return-statement -> return return-follow
29. return-follow -> ;
| expression ;
30. var-follow -> [ expression ]
| empty
31. expression -> additive-expr expression-follow
32. expression-follow -> rel-op additive-expr
| empty
33. rel-op -> <=
| <
| >
| >=
| ==
| !=
34. additive-expr -> term additive-expr-follow
35. additive-expr-follow -> add-op term additive-expr-follow
| empty
36. add-op -> +
| -
37. term -> factor term-follow
38. term-follow -> mul-op factor term-follow
| empty
39. mul-op -> *
| /
| %
40. factor -> ( expression )
| ID id-factor-follow | NUM
41. id-factor-follow -> var-follow
| ( args )
42. args -> arg-list
| empty
43. arg-list -> expression arg-list-follow
44. arg-list-follow -> , expression arg-list-follow
| empty
"""
# 所有终结符的类型
# 终结符是文法中不能再被展开的基本单元,直接来源于词法分析器的 token.type。
# 这些类型用于语法分析过程中与输入 token 的类型进行匹配。
terminal_sign_type = [
'else', # else 关键字
'if', # if 关键字
'int', # int 关键字,表示整型变量
'return', # return 关键字,函数返回语句
'void', # void 关键字,表示无返回值或无参数
'while', # while 关键字,用于循环结构
'addition', # 加法运算符 '+'
'subtraction', # 减法运算符 '-'
'multiplication', # 乘法运算符 '*'
'division', # 除法运算符 '/'
'remainder', # 取余运算符 '%'
'bigger', # 大于操作符 '>'
'bigger-equal', # 大于等于操作符 '>='
'smaller', # 小于操作符 '<'
'smaller-equal', # 小于等于操作符 '<='
'equal', # 等于比较操作符 '=='
'not-equal', # 不等于比较操作符 '!='
'evaluate', # 赋值操作符 '='
'semicolon', # 分号 ';'
'comma', # 逗号 ','
'left-parentheses', # 左圆括号 '('
'right-parentheses', # 右圆括号 ')'
'left-bracket', # 左方括号 '['
'right-bracket', # 右方括号 ']'
'left-brace', # 左花括号 '{'
'right-brace', # 右花括号 '}'
'id', # 标识符,例如变量名、函数名
'num', # 数字常量,例如整数
# 特殊标记:结束符
# 注意:不要在 'pound' 之前添加非终结符类型!这是语法分析器内部使用的结束标志。
'pound' # 输入结束标志 '#'
]
# 所有非终结符的类型
# 非终结符是文法中可以进一步被展开的语法成分,通常由产生式定义。
# 每个非终结符会在语法分析过程中被替换成终结符或其它非终结符组成的序列。
non_terminal_sign_type = [
'program', # 程序整体结构
'define-list', # 定义列表(全局变量和函数定义)
'define', # 单个定义(变量或函数)
'define-type', # 定义类型(变量定义或函数定义)
'var-define-follow', # 变量定义后续部分(如分号或数组声明)
'type', # 类型int 或 void
'fun-define-follow', # 函数定义后续部分(参数列表和函数体)
'params', # 参数列表
'param-list', # 参数列表主体
'param-follow', # 参数后续部分(可能包含更多参数)
'param', # 单个参数定义
'array-subscript', # 数组下标部分 '[ ]'
'code-block', # 代码块 '{ ... }'
'local-define-list', # 局部变量定义列表
'local-var-define', # 局部变量定义
'code-list', # 代码语句列表
'code', # 单条语句(控制结构、表达式等)
'normal-statement', # 正常语句(赋值、声明等)
'normal-statement-follow', # 正常语句后续部分(赋值或函数调用)
'call-follow', # 函数调用后续部分(参数列表)
'call-params', # 函数调用参数列表
'call-param-list', # 函数调用参数主体
'call-param-follow', # 函数调用后续参数处理
'selection-statement', # 选择语句if
'selection-follow', # else 分支
'iteration-statement', # 循环语句while
'iteration-follow', # 循环体(可能是代码块或单条语句)
'return-statement', # 返回语句
'return-follow', # 返回值部分
# 'eval-statement', # 表达式语句(已被注释)
# 'var', # 变量引用(已被注释)
'var-follow', # 变量后续部分(数组访问 [expr]
'expression', # 表达式
'expression-follow', # 表达式后续部分(关系运算符 + 表达式)
'rel-op', # 关系运算符(<=, <, >, >=, ==, !=
'additive-expr', # 加减表达式
'additive-expr-follow', # 加减表达式的递归部分
'add-op', # 加减运算符 '+' 或 '-'
'term', # 项(乘除操作单位)
'term-follow', # 项的递归部分(乘除表达式)
'mul-op', # 乘除余运算符 '*' 或 '/' 或 '%'
'factor', # 因子(基本表达式单元)
'id-factor-follow', # 标识符后的扩展(可能是数组或函数调用)
'args', # 函数调用参数
'arg-list', # 参数列表
'arg-list-follow', # 参数后续部分(多个参数间的递归)
]
# 文法产生式
productions = [
# 0
Production('program', ['define-list'],
'Program0S', [None], 'Program0E'),
# 1
Production('define-list', ['define', 'define-list'],
None, [None, None], 'DefineList0E'),
Production('define-list', [],
None, [], 'DefineList1E'),
# 2
Production('define', ['type', 'id', 'define-type'],
None, [None, None, 'Define0C2'], 'Define0E'),
# 3
Production('define-type', ['var-define-follow'],
'DefineType0S', ['DefineType0C0'], 'DefineType0E'),
Production('define-type', ['fun-define-follow'],
'DefineType1S', ['DefineType1C0'], 'DefineType1E'),
# 4
Production('var-define-follow', ['semicolon'],
None, [None], 'VarDefineFollow0E'),
Production('var-define-follow', ['left-bracket', 'num', 'right-bracket', 'semicolon'],
None, [None, None, None, None], 'VarDefineFollow1E'),
# 5
Production('type', ['int'],
'Type0S', [None], None),
Production('type', ['void'],
'Type1S', [None], None),
# 6
Production('fun-define-follow', ['left-parentheses', 'params', 'right-parentheses', 'code-block'],
None, [None, 'FunDefineFollow0C1', None, 'FunDefineFollow0C3'], 'FunDefineFollow0E'),
# 7
Production('params', ['param-list'],
'Params0S', ['Params0C0'], None),
Production('params', [],
'Params1S', [], None),
# 8
Production('param-list', ['param', 'param-follow'],
None, ['ParamList0C0', 'ParamList0C1'], None),
# 9
Production('param-follow', ['comma', 'param', 'param-follow'],
None, [None, 'ParamFollow0C1', 'ParamFollow0C2'], None),
Production('param-follow', [],
None, [], None),
# 10
Production('param', ['type', 'id', 'array-subscript'],
None, [None, None, None], 'Param0E'),
# 11
Production('array-subscript', ['left-bracket', 'right-bracket'],
'ArraySubscript0S', [None, None], None),
Production('array-subscript', [],
'ArraySubscript1S', [], None),
# 12
Production('code-block', ['left-brace', 'local-define-list', 'code-list', 'right-brace'],
None, [None, 'CodeBlock0C1', 'CodeBlock0C2', None], 'CodeBlock0E'),
# 13
Production('local-define-list', ['local-var-define', 'local-define-list'],
None, ['LocalDefineList0C0', 'LocalDefineList0C1'], None),
Production('local-define-list', [],
None, [], None),
# 14
Production('local-var-define', ['type', 'id', 'var-define-follow'],
None, [None, None, None], 'LocalVarDefine0E'),
# 15
Production('code-list', ['code', 'code-list'],
None, ['CodeList0C0', 'CodeList0C1'], 'CodeList0E'),
Production('code-list', [],
None, [], 'CodeList1E'),
# 16
Production('code', ['normal-statement'],
None, ['Code0C0'], 'Code0E'),
Production('code', ['selection-statement'],
None, ['Code1C0'], 'Code1E'),
Production('code', ['iteration-statement'],
None, ['Code2C0'], 'Code2E'),
Production('code', ['return-statement'],
None, ['Code3C0'], 'Code3E'),
# Production('normal-statement', ['eval-statement', 'semicolon']),
# Production('normal-statement', ['semicolon']),
# 17
Production('normal-statement', ['semicolon'],
None, [None], 'NormalStatement0E'),
Production('normal-statement', ['id', 'normal-statement-follow'],
None, [None, 'NormalStatement1C1'], 'NormalStatement1E'),
# 18
Production('normal-statement-follow', ['var-follow', 'evaluate', 'expression', 'semicolon'],
None, ['NormalStatementFollow0C0', None, 'NormalStatementFollow0C2', None], 'NormalStatementFollow0E'),
Production('normal-statement-follow', ['call-follow', 'semicolon'],
None, ['NormalStatementFollow1C0', None], 'NormalStatementFollow1E'),
# 19
Production('call-follow', ['left-parentheses', 'call-params', 'right-parentheses'],
None, [None, 'CallFollow0C1', None], 'CallFollow0E'),
# 20
Production('call-params', ['call-param-list'],
None, ['CallParams0C0'], 'CallParams0E'),
Production('call-params', [],
None, [], 'CallParams1E'),
# 21
Production('call-param-list', ['expression', 'call-param-follow'],
None, ['CallParamList0C0', 'CallParamList0C1'], 'CallParamList0E'),
# 22
Production('call-param-follow', ['comma', 'expression', 'call-param-follow'],
None, [None, 'CallParamFollow0C1', 'CallParamFollow0C2'], 'CallParamFollow0E'),
Production('call-param-follow', [],
None, [], 'CallParamFollow1E'),
# 23
Production('selection-statement',
['if', 'left-parentheses', 'expression', 'right-parentheses', 'left-brace',
'code-list', 'right-brace', 'selection-follow'],
None, [None, None, 'SelectionStatement0C2', None, None, 'SelectionStatement0C5',
None, 'SelectionStatement0C5'], 'SelectionStatement0E'),
# 24
Production('selection-follow', ['else', 'left-brace', 'code-list', 'right-brace'],
None, [None, None, 'SelectionFollow0C2', None], 'SelectionFollow0E'),
Production('selection-follow', [],
None, [], 'SelectionFollow1E'),
# 25
Production('iteration-statement', ['while', 'left-parentheses', 'expression',
'right-parentheses', 'iteration-follow'],
None, [None, None, 'IterationStatement0C2', None, 'IterationStatement0C4'], 'IterationStatement0E'),
# 26
Production('iteration-follow', ['left-brace', 'code-list', 'right-brace'],
None, [None, 'IterationFollow0C1', None], 'IterationFollow0E'),
Production('iteration-follow', ['code'],
None, ['IterationFollow1C0'], 'IterationFollow1E'),
# 27
Production('return-statement', ['return', 'return-follow'],
None, [None, 'ReturnStatement0C1'], 'ReturnStatement0E'),
# 28
Production('return-follow', ['semicolon'],
None, [None], 'ReturnFollow0E'),
Production('return-follow', ['expression', 'semicolon'],
None, ['ReturnFollow1C0', None], 'ReturnFollow1E'),
# Production('eval-statement', ['var', 'evaluate', 'expression']),
# Production('var', ['id', 'var-follow']),
# 29
Production('var-follow', ['left-bracket', 'expression', 'right-bracket'],
None, [None, 'VarFollow0C1', None], 'VarFollow0E'),
Production('var-follow', [],
None, [], 'VarFollow1E'),
# 30
Production('expression', ['additive-expr', 'expression-follow'],
None, ['Expression0C0', 'Expression0C1'], 'Expression0E'),
# 31
Production('expression-follow', ['rel-op', 'additive-expr'],
None, [None, 'ExpressionFollow0C1'], 'ExpressionFollow0E'),
Production('expression-follow', [],
None, [], 'ExpressionFollow1E'),
# 32
Production('rel-op', ['smaller-equal'],
None, [None], 'RelOp0E'),
Production('rel-op', ['smaller'],
None, [None], 'RelOp1E'),
Production('rel-op', ['bigger'],
None, [None], 'RelOp2E'),
Production('rel-op', ['bigger-equal'],
None, [None], 'RelOp3E'),
Production('rel-op', ['equal'],
None, [None], 'RelOp4E'),
Production('rel-op', ['not-equal'],
None, [None], 'RelOp5E'),
# 33
Production('additive-expr', ['term', 'additive-expr-follow'],
None, ['AdditiveExpr0C0', 'AdditiveExpr0C1'], 'AdditiveExpr0E'),
# 34
Production('additive-expr-follow', ['add-op', 'term', 'additive-expr-follow'],
None, [None, 'AdditiveExprFollow0C1', 'AdditiveExprFollow0C2'], 'AdditiveExprFollow0E'),
Production('additive-expr-follow', [],
None, [], 'AdditiveExprFollow1E'),
# 35
Production('add-op', ['addition'],
None, [None], 'AddOp0E'),
Production('add-op', ['subtraction'],
None, [None], 'AddOp1E'),
# 36
Production('term', ['factor', 'term-follow'],
None, ['Term0C0', 'Term0C1'], 'Term0E'),
# 37
Production('term-follow', ['mul-op', 'factor', 'term-follow'],
None, [None, 'TermFollow0C1', 'TermFollow0C2'], 'TermFollow0E'),
Production('term-follow', [],
None, [], None),
# 38
Production('mul-op', ['multiplication'],
None, [None], 'MulOp0E'),
Production('mul-op', ['division'],
None, [None], 'MulOp1E'),
Production('mul-op', ['remainder'],
None, [None], 'MulOp2E'),
# 39
Production('factor', ['left-parentheses', 'expression', 'right-parentheses'],
None, [None, 'Factor0C1', None], 'Factor0E'),
Production('factor', ['id', 'id-factor-follow'],
None, [None, 'Factor1C1'], 'Factor1E'),
Production('factor', ['num'],
None, [None], 'Factor2E'),
# 40
Production('id-factor-follow', ['var-follow'],
None, [None], 'IdFactorFollow0E'),
Production('id-factor-follow', ['left-parentheses', 'args', 'right-parentheses'],
None, [None, 'IdFactorFollow1C1', None], 'IdFactorFollow1E'),
# 41
Production('args', ['arg-list'],
None, ['Args0C0'], 'Args0E'),
Production('args', [],
None, [], 'Args1E'),
# 42
Production('arg-list', ['expression', 'arg-list-follow'],
None, ['ArgList0C0', 'ArgList0C1'], 'ArgList0E'),
Production('arg-list-follow', ['comma', 'expression', 'arg-list-follow'],
None, [None, 'ArgListFollow0C1', 'ArgListFollow0C2'], 'ArgListFollow0E'),
Production('arg-list-follow', [],
None, [], 'ArgListFollow1E')
]
# 文法开始符号
grammar_start = Sign('program')

View File

@ -4,91 +4,6 @@ from semantic.code import get_temp_block_name, get_temp_var_name
"""
添加语义规则的文法
0. program{code} ->{.init} define-list
1. define-list{code} -> define define-list
{code} | empty
2. define{code} -> type ID define-type{type id}
3. define-type{code .enter} ->{.judge} var-define-follow{type id}
{code} |{.judge} fun-define-follow{type fun}
4. var-define-follow{type} -> ;
{type length} | [ NUM ] ;
5. type ->{type} int
|{type} void
6. fun-define-follow{code} -> ( params{type fun} ) code-block{fun}
7. params{.create} -> param-list{fun}
{.create} | empty
8. param-list -> param{fun} param-follow{fun}
9. param-follow -> , param{fun} param-follow{fun}
| empty
10. param -> type ID array-subscript
11. array-subscript{type} -> [ ]
{type} | empty
12. code-block{code} -> { local-define-list{fun} code-list{fun} }
13. local-define-list -> local-var-define{fun} local-define-list{fun}
| empty
14. local-var-define -> type ID var-define-follow
15. code-list{code} -> code{fun} code-list{fun}
| empty
16. code{code} -> normal-statement{fun}
| selection-statement{fun}
| iteration-statement{fun}
| return-statement{fun}
17. normal-statement -> ;
| ID normal-statement-follow{fun id}
18. normal-statement-follow{code} -> var-follow{fun} = expression{fun} ;
{code} | call-follow{fun id} ;
19. call-follow{code} -> ( call-params{fun id} )
20. call-params{code} -> call-param-list{fun}
| empty
21. call-param-list{num code} -> expression{fun} call-param-follow{fun}
22. call-param-follow{num code names} -> , expression{fun} call-param-follow{fun}
| empty
23. selection-statement{code} -> if ( expression{fun} ) { code-list{fun} } selection-follow{fun}
24. selection-follow{code} -> else { code-list{fun} }
{code} | empty
25. iteration-statement -> while ( expression{fun} ) iteration-follow{fun}
26. iteration-follow{code} -> { code-list{fun} }
{code} | code{fun}
27. return-statement{code} -> return return-follow{fun}
28. return-follow -> ;
| expression{fun} ;
29. var-follow{code name type} -> [ expression{fun} ]
{type} | empty
30. expression{code name bool} -> additive-expr{fun} expression-follow{fun}
31. expression-follow{bool code op name} -> rel-op additive-expr{fun}
{bool} | empty
32. rel-op{op} -> <=
| <
| >
| >=
| ==
| !=
33. additive-expr{name code} -> term{fun} additive-expr-follow{fun}
34. additive-expr-follow{add op code name} -> add-op term{fun} additive-expr-follow{fun}
{add} | empty
35. add-op{op} -> +
| -
36. term{name code} -> factor{fun} term-follow{fun}
37. term-follow{mul op code name} -> mul-op factor{fun} term-follow{fun}
{mul} | empty
38. mul-op{op} -> *
| /
| %
39. factor{name code} -> ( expression{fun} )
| ID id-factor-follow{id fun}
| NUM
40. id-factor-follow -> var-follow{fun}
| ( args{fun} )
41. args{code num} -> arg-list{fun}
| empty
42. arg-list{code num} -> expression{fun} arg-list-follow{fun}
43. arg-list-follow{code num names} -> , expression{fun} arg-list-follow{fun}
| empty
"""
# 定义一个符号表池,每次调用函数的时候使用深拷贝从这里取局部变量表
symbol_table_pool = SymbolTablePool()
@ -389,6 +304,8 @@ class SemanticRuleFactory:
return IterationStatement48E(node)
# 49
if rule_key == 'ReturnStatement49C1':
return ReturnStatement49C1(node)
if rule_key == 'ReturnStatement49E':
return ReturnStatement49E(node)
@ -397,6 +314,8 @@ class SemanticRuleFactory:
return ReturnFollow50E(node)
# 51
if rule_key == 'ReturnFollow51C0':
return ReturnFollow51C0(node)
if rule_key == 'ReturnFollow51E':
return ReturnFollow51E(node)
@ -556,8 +475,17 @@ class SemanticRuleFactory:
# 82
if rule_key == 'ArrayListWithNum82E':
return ArrayListWithNum82E(node)
# 84
if rule_key == 'MulOp84E':
return MulOp84E(node)
return None
return None
# S 产生式开始
# E 产生式结束
# CN 产生式第N个元素应用之后
@ -1283,11 +1211,11 @@ class CallFollow39E(SemanticRule):
def __rule(self, node):
if symbol_table_pool.fun_table.exist(node.id):
if node.children[1].num != symbol_table_pool.query(node.id).get_params_num():
self.errors.append(f"错误 : 调用函数{node.id}的参数与实际参数不匹配")
self.errors.append(SemanticError(f"错误 : 调用函数{node.id}的参数与实际参数不匹配"))
for c in node.children[1].code:
node.code.append(c)
else:
self.errors.append(f"错误 : 调用函数{node.id}不存在")
self.errors.append(SemanticError(f"错误 : 调用函数{node.id}不存在"))
@ -1397,23 +1325,25 @@ class SelectionStatement45E(SemanticRule):
else:
for c in node.children[1].code:
node.code.append(c)
if_block = get_temp_block_name()
else_block = get_temp_block_name()
next_block = get_temp_block_name()
node.code.append(f"(if, {node.children[1].name}, goto, {if_block})")
if_block = get_temp_block_name()
else_block = get_temp_block_name()
next_block = get_temp_block_name()
node.code.append(f"(block, _, _, {if_block})")
for c in node.children[3].code:
node.code.append(c)
node.code.append(f"goto, _, _, {next_block}")
node.code.append(f"(block, _, _, {else_block})")
for c in node.children[5].code:
node.code.append(c)
node.code.append(f"(goto, _, _, {next_block})")
node.code.append(f"(if, {node.children[1].name}, goto, {if_block})")
node.code.append(f"(block, _, _, {next_block})")
node.code.append(f"(block, _, _, {if_block})")
for c in node.children[3].code:
node.code.append(c)
node.code.append(f"(goto, _, _, {next_block})")
node.code.append(f"(block, _, _, {else_block})")
for c in node.children[5].code:
node.code.append(c)
node.code.append(f"(goto, _, _, {next_block})")
node.code.append(f"(block, _, _, {next_block})")
class SelectionFollow46C2(SemanticRule):
def execute(self):
@ -1462,7 +1392,7 @@ class IterationStatement48E(SemanticRule):
node.code.append(f"(block, _, _, {judge_block})")
for c in node.children[1].code:
node.code.append(c)
node.code.append(f"(if, {node.children[2].name}, goto, {iteration_block})")
node.code.append(f"(if, {node.children[1].name}, goto, {iteration_block})")
node.code.append(f"(goto, _, _, {next_block})")
node.code.append(f"(block, _, _, {iteration_block})")
for c in node.children[3].code:
@ -1470,6 +1400,13 @@ class IterationStatement48E(SemanticRule):
node.code.append(f"(goto, _, _, {judge_block})")
node.code.append(f"(block, _, _, {next_block})")
class ReturnStatement49C1(SemanticRule):
def execute(self):
return self.__rule(self.node)
def __rule(self, node):
node.fun = node.parent.fun
class ReturnStatement49E(SemanticRule):
def execute(self):
self.__rule(self.node)
@ -1485,6 +1422,13 @@ class ReturnFollow50E(SemanticRule):
def __rule(self, node):
node.code.append("(return, _, _, _)")
class ReturnFollow51C0(SemanticRule):
def execute(self):
self.__rule(self.node)
def __rule(self, node):
node.fun = node.parent.fun
class ReturnFollow51E(SemanticRule):
def execute(self):
@ -1502,16 +1446,15 @@ class Exp52C0(SemanticRule):
self.__rule(self.node)
def __rule(self, node):
self.fun = node.parent.fun
print("52C0")
print(self.fun)
node.fun = node.parent.fun
class Exp52C1(SemanticRule):
def execute(self):
self.__rule(self.node)
def __rule(self, node):
self.fun = node.parent.fun
node.fun = node.parent.fun
class Exp52E(SemanticRule):
def execute(self):
@ -1613,8 +1556,7 @@ class AdditiveExpr61C0(SemanticRule):
def __rule(self, node):
node.fun = node.parent.fun
print("61C0")
print(node.parent.fun)
class AdditiveExpr61C1(SemanticRule):
def execute(self):
@ -1622,8 +1564,6 @@ class AdditiveExpr61C1(SemanticRule):
def __rule(self, node):
node.fun = node.parent.fun
print("61C1")
print(node.parent.fun)
class AdditiveExpr61E(SemanticRule):
@ -1716,8 +1656,7 @@ class Term66C0(SemanticRule):
def __rule(self, node):
node.fun = node.parent.fun
print("66C0")
print(node.fun)
class Term66C1(SemanticRule):
def execute(self):
@ -1832,8 +1771,7 @@ class Factor72C1(SemanticRule):
def __rule(self, node):
node.id = node.get_pre_brother(1).lexical
node.fun = node.parent.fun
print("72C1")
print(node.fun)
class Factor72E(SemanticRule):
def execute(self):
@ -1857,8 +1795,7 @@ class IdFactorFollow74E(SemanticRule):
self.__rule(self.node)
def __rule(self, node):
print("74E")
print(node.fun)
if symbol_table_pool.query(node.fun).exist(node.id):
if node.children[0].type == "var":
node.name = node.id
@ -1867,10 +1804,10 @@ class IdFactorFollow74E(SemanticRule):
node.name = get_temp_var_name()
for c in node.children[0].code:
node.code.append(c)
node.code.append("(=[], " + node.id, + ", " + node.children[0].name + ", " + node.name)
node.code.append(f"(=[], {node.id}, {node.children[0].name}, {node.name})")
else:
self.errors.append('变量' + node.id + '未定义')
self.errors.append(SemanticError('变量' + node.id + '未定义'))
class IdFactorFollow75C1(SemanticRule):
def execute(self):
@ -1886,7 +1823,7 @@ class IdFactorFollow75E(SemanticRule):
def __rule(self, node):
if symbol_table_pool.fun_table.exist(node.id):
if node.children[1].num != symbol_table_pool.query(node.id).get_params_num():
self.errors.append('调用函数' + node.id + ', 参数数量不匹配')
self.errors.append(SemanticError('调用函数' + node.id + ', 参数数量不匹配'))
else:
for c in node.children[1].code:
@ -1896,7 +1833,7 @@ class IdFactorFollow75E(SemanticRule):
node.code.append('(=, result, _, ' + node.name + ')')
else:
self.errors.append('函数' + node.id + '未定义')
self.errors.append(SemanticError('函数' + node.id + '未定义'))
class Args76C0(SemanticRule):
def execute(self):
@ -1946,9 +1883,9 @@ class ArgList78E(SemanticRule):
node.code.append(c)
for c in node.children[1].code:
node.code.append(c)
node.code.append("(param, _, _, )" + node.children[0].name)
node.code.append(f"(param, _, _, {node.children[0].name})")
for name in node.children[1].names:
node.code.append("(param, _, _, )" + name)
node.code.append(f"(param, _, _, {name})")
class ArgListFollow79C1(SemanticRule):
def execute(self):
@ -1994,3 +1931,11 @@ class Factor83E(SemanticRule):
def __rule(self, node):
node.name = get_temp_var_name()
node.code.append("(=, " + node.children[0].lexical, +", _, ", node.name)
class MulOp84E(SemanticRule):
def execute(self):
self.__rule(self.node)
def __rule(self, node):
node.op = node.children[0].lexical

View File

@ -1,3 +1,5 @@
from prettytable import PrettyTable
class Symbol:
"""
符号基类
@ -86,21 +88,21 @@ class SymbolTablePool:
self.fun_table = FunTable()
# 添加 output 和 input 的支持
self.local_var_tables.append(
LocalVarTable('input', self.global_var_table)
)
self.local_var_tables.append(
LocalVarTable('output', self.global_var_table)
)
self.query('output').append(
LocalVar('output_name', 'i32', 4, True)
)
self.fun_table.append(
Fun('input', 'i32', self.query('input'))
)
self.fun_table.append(
Fun('output', 'void', self.query('output'))
)
# self.local_var_tables.append(
# LocalVarTable('input', self.global_var_table)
# )
# self.local_var_tables.append(
# LocalVarTable('output', self.global_var_table)
# )
# self.query('output').append(
# LocalVar('output_name', 'i32', 4, True)
# )
# self.fun_table.append(
# Fun('input', 'i32', self.query('input'))
# )
# self.fun_table.append(
# Fun('output', 'void', self.query('output'))
# )
def change_fun_type(self, fun_name, type):
"""
@ -130,21 +132,48 @@ class SymbolTablePool:
self.local_var_tables.append(local_var_table)
def debug(self):
# Global Variable Table
print("Global Variable Table:")
table = PrettyTable()
table.field_names = ["Name", "Type", "Width", "Offset"]
for symbol in self.global_var_table._table:
print(vars(symbol))
table.add_row([
getattr(symbol, "name", ""),
getattr(symbol, "type", ""),
getattr(symbol, "width", ""),
getattr(symbol, "offset", "")
])
print(table)
# Function Table
print("\nFunction Table:")
fun_table = PrettyTable()
fun_table.field_names = ["Function Name", "Return Type", "Local Var Table"]
for fun in self.fun_table._table:
print(f"Function: {fun.name}, Return Type: {fun.return_type}")
if hasattr(fun, 'table'):
print(f" Local Variable Table ({fun.table.name}):")
for local_var in fun.table._table:
print(f" {vars(local_var)}")
local_table_name = getattr(fun, "table", None)
local_table_name = local_table_name.name if local_table_name else ""
fun_table.add_row([
fun.name,
getattr(fun, "return_type", ""),
local_table_name
])
print(fun_table)
# Local Variable Tables
print("\nLocal Variable Tables:")
for table in self.local_var_tables:
print(f"LocalVarTable: {table.name}")
for symbol in table._table:
print(f" {vars(symbol)}")
for table_obj in self.local_var_tables:
print(f"LocalVarTable: {table_obj.name}")
local_table = PrettyTable()
local_table.field_names = ["Name", "Type", "Width", "Offset", "Is Param"]
for symbol in table_obj._table:
local_table.add_row([
getattr(symbol, "name", ""),
getattr(symbol, "type", ""),
getattr(symbol, "width", ""),
getattr(symbol, "offset", ""),
getattr(symbol, "is_param", "")
])
print(local_table)
class GlobalVarTable(SymbolTable):

File diff suppressed because it is too large Load Diff

View File

@ -177,6 +177,7 @@ terminal_sign_type = [
'subtraction',
'multiplication',
'division',
'yushu',
'bigger',
'bigger-equal',
'smaller',
@ -551,7 +552,7 @@ productions = [
),
# 49
Production('return-statement', ['return', 'return-follow'],
None, [None, None], "ReturnStatement49E",
None, [None, 'ReturnStatement49C1'], "ReturnStatement49E",
),
# 50
Production('return-follow', ['semicolon'],
@ -559,7 +560,7 @@ productions = [
),
# 51
Production('return-follow', ['exp', 'semicolon'],
None, [None, None], 'ReturnFollow51E',
None, ['ReturnFollow51C0', None], 'ReturnFollow51E',
),
# 52
Production('exp', ['additive-expr', 'exp-follow'],
@ -647,7 +648,7 @@ productions = [
None, [None, 'ArgListFollow79C1', 'ArgListFollow79C2'], 'ArgListFollow79E'),
# 80
Production('arg-list-follow', [],
None, [], 'ArgListFollowE'),
None, [], 'ArgListFollow80E'),
# 81
Production('arraylist-with-num', [],
@ -661,6 +662,10 @@ productions = [
# 83
Production('factor', ['float-num'],
None, [None], 'Factor83E'),
# 84
Production('mul-op', ['yushu'],
None, [None], 'MulOp84E'),
]
# 文法开始符号

View File

@ -254,6 +254,7 @@ class Node:
self.lexical = None
self.array = None
self.code = list()
self.name = None
self.type = None
self.id = None
self.length = None

18
test.c
View File

@ -1,18 +0,0 @@
/* A program to perform Euclid s Algorithm to compute gcd. */
int gcd(int u, int v) {
if (v == 0) {
return u;
} else {
return gcd(v, u-u/v*v);
}
/* u-u/v*v* == u mod v */
}
void main() {
int x;
int y;
x = input();
y = input();
output(gcd(x, y));
return;
}

View File

@ -1,17 +1,18 @@
/*test1斐波那契数列控制流 + 函数调用*/
int fib(int n) {
if (n < 1){
return n;
} else {
return fib(n - 1) + fib(n - 2);
}
}
int main() {
int y;
int x;
x = 5 * 2 + 2;
a = 2 == 2;
x = fib(6);
return x;
}
/*test1斐波那契数列控制流 + 函数调用*/
fn fib(n:i32) -> i32 {
if n < 1 {
return n;
} else {
return fib(n - 1) + fib(n - 2);
}
}
fn main() {
i32 x;
i32 y;
x = 5 * 2 + 2;
a = 2 == 2;
x = fib(6);
return x;
}

14
test2.c
View File

@ -1,14 +0,0 @@
/* test2阶乘计算while 循环 + 局部变量)*/
int fact(int n) {
int result;
result = 1;
while (n > 0) {
result = result * n;
n = n - 1;
}
return result;
}
int main() {
return fact(5);
}

16
test2.hy Normal file
View File

@ -0,0 +1,16 @@
// test2阶乘计算while 循环 + 局部变量
fn fact(n: i32) {
i32 result;
result = 1;
while n > 0 {
result = result * n;
n = n - 1;
}
return result;
}
fn main() {
return fact(5);
}

21
test3.c
View File

@ -1,21 +0,0 @@
/* test3多函数协作函数调用 + 全局变量)*/
int a;
int b;
int sum() {
return a + b;
}
int product() {
return a * b;
}
int main() {
int s;
int p;
a = 3;
b = 4;
s = sum();
p = product();
return s + p;
}

22
test3.hy Normal file
View File

@ -0,0 +1,22 @@
// test3多函数协作函数调用 + 全局变量
i32 a;
i32 b;
fn sum() {
return a + b;
}
fn product() {
return a * b;
}
fn main() {
i32 s;
i32 p;
a = 3;
b = 4;
// s = sum(a);
s = sum();
p = product();
return s + p;
}

19
test4.c
View File

@ -1,19 +0,0 @@
/* test4嵌套 if 判断(复杂控制流)*/
int max(int x, int y) {
if (x > y) {
return x;
}
else {
return y;
}
}
int main() {
int a;
int b;
int c;
a = 10;
b = 20;
c = max(a, b);
return c;
}

20
test4.hy Normal file
View File

@ -0,0 +1,20 @@
// test4嵌套 if 判断复杂控制流
fn max(x: i32, y: i32) -> i32 {
if x > y {
return x;
} else {
return y;
}
}
fn main() {
i32 a;
i32 b;
i32 c;
a = 10;
b = 20;
c = max(a, b);
return c;
}

29
test5.c
View File

@ -1,29 +0,0 @@
/* test5冒泡排序数组访问模拟*/
int swap(int i, int j) {
int temp;
temp = i;
i = j;
j = temp;
return 0;
}
int main() {
int a;
int b;
int c;
int d;
int e;
a = 5;
b = 3;
c = 8;
d = 1;
e = 9;
/* 冒泡排序模拟 */
if (a > b) { swap(a, b); }
if (b > c) { swap(b, c); }
if (c > d) { swap(c, d); }
if (d > e) { swap(d, e); }
return e;
}

20
test5.hy Normal file
View File

@ -0,0 +1,20 @@
// while + if
fn is_prime(n:i32) -> i32 {
i32 i;
if n <= 1 {
return 0;
}
i = 2;
while i * i <= n {
if n % i == 0 {
return 0;
}
i = i + 1;
}
return 1;
}
fn main() {
return is_prime(17);
}

13
test6.c
View File

@ -1,13 +0,0 @@
/* test6逻辑表达式优先级测试 */
int main() {
int a;
int b;
int c;
a = 1;
b = 2;
c = 3;
int result;
result = a == 1 && b < c || c != 4;
return result;
}

View File

@ -1,19 +1,19 @@
/* test8带错误的语法测试用于验证报错机制*/
int main() {
int x;
x = ; /* 错误:缺少右值 */
return x;
}
int main1() {
int x;
x == 10; /* 错误:应为赋值 = */
return x;
}
int main2() {
int x;
if (x) /* 错误if 条件必须是整型表达式 */
return 1;
return 0;
}
/* test6带错误的语法测试用于验证报错机制*/
fn main() {
i32 x;
x = ; /* 错误:缺少右值 */
return x;
}
fn main1() {
int x;
x == 10; /* 错误:应为赋值 = */
return x;
}
fn main2() {
i32 x;
if (x) /* 错误if 条件必须是整型表达式 */
return 1;
return 0;
}

19
test7.c
View File

@ -1,19 +0,0 @@
/* test7嵌套循环while + if*/
int is_prime(int n) {
int i;
if (n <= 1) {
return 0;
}
i = 2;
while (i * i <= n) {
if (n % i == 0) {
return 0;
}
i = i + 1;
}
return 1;
}
int main() {
return is_prime(17);
}

29
test7.hy Normal file
View File

@ -0,0 +1,29 @@
i32 g_a;
fn main() -> i32 {
i32 type;
i32 foo;
i32 age;
i32 a;
age = 32;
if foo >= 60 {
a = 0;
} else {
if foo >= 18 {
a = 1;
} else {
a = 2;
}
}
while foo <= 100 {
age = age + a;
a = a + 1;
}
return 0;
}

View File

@ -1,9 +0,0 @@
fn main() {
i32 a;
a = 42;
if a {
}
}

67
tk_ui.py Normal file
View File

@ -0,0 +1,67 @@
import tkinter as tk
from tkinter import scrolledtext, messagebox
from lexical.lexical import Lexical
from syntax.syntax import Syntax
def process_code(input_code):
lexical = Lexical()
lexical.load_source(input_code)
lexical_success = lexical.execute()
output = []
if lexical_success:
lexical_result = lexical.get_result()
output.append('词法分析是否成功:\t' + str(lexical_success))
output.append('\n词法分析结果:')
for i in lexical_result:
output.append(f"{i.type} {i.str} {i.line}")
output.append('')
syntax = Syntax()
syntax.put_source(lexical_result)
syntax_success = syntax.execute()
output.append('语法分析和语义分析是否成功\t' + str(syntax_success))
if syntax_success:
output.append('\n语义分析结果:\t')
output.append('四元式代码:\t')
i = -1
for code in syntax.get_result().root.code:
i += 1
output.append(f"{i} \t{code}")
return '\n'.join(output), ''
else:
return '\n'.join(output), '错误原因:\t' + syntax.get_error().info
else:
return '', '错误原因:\t' + lexical.get_error().info
def on_submit():
input_code = input_text.get("1.0", tk.END)
output_text.delete("1.0", tk.END)
error_label.config(text="")
try:
result, error = process_code(input_code)
if result:
output_text.insert(tk.END, result)
if error:
error_label.config(text=error)
except Exception as e:
messagebox.showerror("程序异常", str(e))
root = tk.Tk()
root.title("C 语言编译器前端演示")
# 输入框
input_text = scrolledtext.ScrolledText(root, width=80, height=20)
input_text.pack(padx=10, pady=5)
# 提交按钮
submit_btn = tk.Button(root, text="提交", command=on_submit)
submit_btn.pack(pady=5)
# 输出框
output_text = scrolledtext.ScrolledText(root, width=80, height=20, bg="#000000")
output_text.pack(padx=10, pady=5)
# 错误信息框
error_label = tk.Label(root, text="", fg="red")
error_label.pack(pady=5)
root.mainloop()