好友
阅读权限10
听众
最后登录1970-1-1
|
# .ch 文件中文解释器
## 项目简介
这是一个使用 C++ 实现的 `.ch` 文件中文解释器,直接解析并执行 `.ch` 后缀文件,无需转换为其他语言。解释器采用类 C++ 的编译解析逻辑,所有关键字均使用中文,支持变量定义、函数定义、基本运算、控制台输出、数组操作、结构体、文件操作和流程控制等核心功能。
**主要特性:**
- ✅ 完整的错误定位系统,所有错误都包含精确的行号信息
- ✅ 智能类型系统:整型运算返回整型,浮点数运算返回浮点数
- ✅ 多维数组支持:支持1-5维数组,最多5维,语法类似C/C++
- ✅ 完整的数组支持:数组定义、初始化、元素访问和赋值
- ✅ 动态数组大小支持:支持使用变量和表达式作为数组大小,语法灵活
- ✅ 文件读写操作:支持文件读取、写入和追加操作
- ✅ 结构体定义和成员访问:支持结构体定义、变量实例化和成员访问
- ✅ 结构体成员赋值:支持直接对结构体成员进行赋值操作
- ✅ 函数重载:支持同名函数不同参数
- ✅ 函数作用域限制:全局作用域只允许变量定义和结构体定义
- ✅ 函数返回类型检查:确保函数返回类型与定义一致
- ✅ 否则如果语句:支持完整的if-else if-else条件判断链
- ✅ ASCII字符兼容:完全支持ASCII码表和中文字符
- ✅ 严格的代码规范:移除所有简化处理,提高代码健壮性
- ✅ 精确错误处理:移除所有"假设"和"默认"处理,提供详细错误信息
- ✅ 系统命令行:支持系统命令行执行功能,类似system()函数
- ✅ 字符类型支持:新增字符型数据类型和字符字面量支持
- ✅ 基础类型转换:提供基础的类型转换功能,包括整数、浮点数、布尔值转换
## 目录结构
```
chplus/
├── main.cpp # 主程序入口
├── CMakeLists.txt # CMake构建配置文件
├── README.md # 项目文档
├── include/ # 头文件目录
│ ├── lexer.h # 词法分析器头文件
│ ├── parser.h # 语法分析器头文件
│ └── interpreter.h # 执行器头文件
├── src/ # 源代码目录
│ ├── lexer/ # 词法分析器实现
│ ├── parser/ # 语法分析器实现
│ ├── executor/ # 执行器实现
│ └── utils/ # 工具函数
├── examples/ # 示例文件目录
├── ch_Lib/ # 标准库目录
│ ├── math.ch # 完整数学库 (100%中文化)
│ ├── string.ch # 完整字符串库 (100%中文化)
│ ├── file.ch # 完整文件库 (100%中文化)
│ ├── readme.math.ch.md # 数学库详细文档
│ ├── readme.string.ch.md # 字符串库详细文档
│ └── readme.file.ch.md # 文件库详细文档
└── tests/ # 测试文件目录
```
## 模块化编程与导入功能
.ch解释器支持模块化编程,允许通过导入功能将代码组织成多个文件。
### 导入语法
```ch
导入("ch_Lib/库名.ch");
```
### 标准库概述
.ch解释器提供了三个核心标准库,全部使用中文函数名:
#### 1. 数学库 (math.ch)
完整的C++ cmath功能实现,包含:
- **三角函数**: sin, cos, tan, asin, acos, atan
- **双曲函数**: sinh, cosh, tanh
- **指数对数**: exp, log, log10, sqrt, cbrt
- **取整函数**: ceil, floor, round, trunc
- **绝对值函数**: abs, fabs
- **其他函数**: fmod, gcd, lcm等
- **数学常量**: PI, E, SQRT2等
**使用示例:**
```ch
导入("ch_Lib/math.ch");
定义(空类型) 主函数() {
定义(小数) radius = 5.0;
定义(小数) area = PI * radius * radius;
控制台输出("圆的面积: " + area); // 输出: 78.539815
}
```
#### 2. 字符串库 (string.ch)
完整的C++ string功能实现,包含:
- **基础操作**: 连接、重复、子串、长度
- **转换功能**: 转大写、转小写、去空白
- **查找功能**: 查找、反向查找、替换
- **验证功能**: 为数字、为字母、为空白
- **字符操作**: 获取字符、翻转、计数
- **高级功能**: 填充、分割、连接
- **类型转换**: 整数转字符串、小数转字符串、布尔值转字符串、字符串转数值
- **内置优化**: 长度、子串、查找等核心函数直接集成在解释器中,性能优化
**使用示例:**
```ch
导入("ch_Lib/string.ch");
定义(空类型) 主函数() {
定义(字符串) text = "Hello World";
控制台输出(长度(text)); // 输出: 11
控制台输出(子串(text, 0, 5)); // 输出: Hello
控制台输出(查找(text, "World")); // 输出: 6
控制台输出(转大写(text)); // 输出: HELLO WORLD
控制台输出(转小写(text)); // 输出: hello world
// 类型转换示例
定义(整型) num = 123;
控制台输出(整数转字符串(num)); // 输出: 123
定义(小数) pi = 3.14159;
控制台输出(小数转字符串(pi)); // 输出: 3.14
// 高级操作
定义(字符串) messy = " hello ";
控制台输出(去空白(messy)); // 输出: hello
控制台输出(重复("Hi", 3)); // 输出: HiHiHi
}
```
#### 3. 文件库 (file.ch)
完整的C++文件操作和freopen功能实现,包含:
- **文件重定向**: 类似freopen的流重定向功能
- **文件读写**: 读取、写入、追加文件
- **文件系统**: 检查存在、获取大小、路径操作
- **目录操作**: 创建、删除、重命名
- **文本处理**: 逐行读取、分割、合并
- **临时文件**: 创建临时文件、获取系统目录
**使用示例:**
```ch
导入("ch_Lib/file.ch");
定义(空类型) 主函数() {
// 文件重定向
重定向标准输出("log.txt");
控制台输出("这条信息写入文件");
恢复标准输出();
// 文件操作
如果 (文件存在("config.txt")) {
定义(字符串) content = 读取文件("config.txt");
控制台输出("配置文件内容: " + content);
}
}
```
### 循环导入检测
导入功能内置循环导入检测,防止:
- 文件A导入B,B又导入A
- 多层循环导入链
- 嵌套导入循环
**安全特性:**
- 自动检测循环依赖
- 防止无限递归
- 错误提示和回滚机制
### 导入功能使用指南
1. **导入位置**:导入语句通常放在程序开头
2. **相对路径**:支持相对路径和绝对路径
3. **库结构**:建议将库文件放在ch_Lib目录
4. **循环检测**:避免创建循环依赖关系
**最佳实践:**
```ch
// 导入多个库
导入("ch_Lib/math.ch");
导入("ch_Lib/string.ch");
导入("ch_Lib/file.ch");
// 在主函数中使用库功能
定义(空类型) 主函数() {
// 使用数学库
定义(小数) result = sin(30) + cos(60);
// 使用字符串库
定义(字符串) msg = 连接("计算结果: ", 整数转字符串(result));
// 使用文件库
写入文件("result.txt", msg);
// 使用系统命令行
系统命令行("echo 系统命令行功能演示");
系统命令行("dir");
}
```
## 系统命令行功能
.ch解释器支持系统命令行执行功能,类似于C++中的`system()`函数。
### 语法
```ch
系统命令行("要执行的命令");
```
### 功能特性
- **直接执行**:使用系统的shell环境执行命令
- **返回值处理**:获取命令执行的返回码
- **表达式支持**:支持作为表达式使用,返回命令执行结果
- **文件操作集成**:与文件库完美集成,支持文件读取
- **错误报告**:命令执行失败时显示错误信息
- **中文友好**:支持中文路径和中文命令
### 使用示例
```ch
定义(空类型) 主函数() {
// 传统系统命令行语句(不返回值)
系统命令行("echo Hello World");
系统命令行("dir");
// 系统命令行表达式(返回命令执行结果)
定义(字符串) result = 系统命令行("echo 测试");
控制台输出("命令结果: " + result);
// 文件操作
系统命令行("mkdir new_folder");
// 读取文件内容(改进版)
导入("ch_Lib/file.ch");
定义(字符串) fileContent = 读取文件("test.txt");
控制台输出("文件内容: " + fileContent);
}
```
### 实际应用
系统命令行功能特别适合用于:
- **文件管理**:创建、删除、复制、移动文件和目录
- **系统信息**:获取时间、用户信息、系统状态
- **网络操作**:ping、curl、wget等网络工具
- **程序调用**:执行外部程序和脚本
- **自动化任务**:批量处理和系统维护
## 语法说明
### 变量定义
变量定义遵循固定格式:`定义(数据类型) 变量名;`,支持变量初始化和数组定义。
**示例:**
```ch
// 基本类型
定义(整型) a = 10;
定义(字符串) b = "测试内容";
定义(小数) pi = 3.14;
定义(布尔型) isActive = 真; // 布尔型变量
定义(字符型) ch = 'A'; // 字符型变量
定义(整型) c;
// 数组类型
定义(整型) arr[10]; // 整型数组
定义(字符串) names[5]; // 字符串数组
定义(小数) prices[100]; // 小数数组
定义(布尔型) flags[5]; // 布尔型数组
定义(字符型) chars[26]; // 字符型数组
// 结构体数组(新增功能)
定义(结构体) Point {
整型 x;
整型 y;
};
定义(Point) points[10]; // 结构体数组
```
### 函数定义
函数定义规则与变量定义一致,无需额外显式声明「函数」关键字,`定义()`内填写返回值类型(可留空对应无返回值)。
**重要约束:**
- 函数作用域限制:全局作用域(主函数之外)只能定义变量和结构体,不允许执行其他操作(如文件读写、控制台输出等)
- 函数重载:支持同名函数不同参数类型
- 返回类型检查:函数返回类型必须与定义一致
**示例:**
```ch
// 无返回值主函数
定义(空类型) 主函数() {
控制台输出("Hello World");
}
// 有参数有返回值函数
定义(整型) 求和函数(定义(整型) x, 定义(整型) y) {
定义(整型) result = x + y;
返回 result;
}
// 函数重载示例
定义(整型) 计算(定义(整型) a, 定义(整型) b) {
返回 a + b;
}
定义(小数) 计算(定义(小数) a, 定义(小数) b) {
返回 a + b;
}
定义(字符串) 计算(定义(字符串) a, 定义(字符串) b) {
返回 a + b;
}
// 空类型函数示例
定义(空类型) printMessage(定义(字符串) msg) {
控制台输出(msg);
// 可以使用返回退出函数,但不返回值
返回;
}
```
### 流程控制
**if-else if-else 语句:**
```ch
如果 (条件) {
// 条件为真时执行
} 否则如果 (其他条件) {
// 第一个条件为假,其他条件为真时执行
} 否则 {
// 所有条件为假时执行
}
```
**示例:**
```ch
定义(整型) score = 85;
如果 (score >= 90) {
控制台输出("成绩优秀");
} 否则如果 (score >= 80) {
控制台输出("成绩良好");
} 否则如果 (score >= 70) {
控制台输出("成绩中等");
} 否则如果 (score >= 60) {
控制台输出("成绩及格");
} 否则 {
控制台输出("成绩不及格");
}
```
### 控制台输入输出
**控制台输出:**
使用 `控制台输出()` 函数进行输出:
```ch
控制台输出("Hello World");
控制台输出(a + b);
```
**控制台输入:**
使用 `控制台输入()` 函数进行输入:
```ch
控制台输入(年龄); // 从控制台读取输入到变量年龄
```
**文件操作:**
**文件写入:**
使用 `文件写入()` 函数创建或覆盖文件:
```ch
定义(字符串) content = "这是文件内容";
文件写入("example.txt", content);
```
**文件读取:**
使用 `文件读取()` 函数从文件读取内容:
```ch
定义(字符串) fileContent;
文件读取("example.txt", fileContent);
控制台输出("文件内容: " + fileContent);
```
**文件追加:**
使用 `文件追加()` 函数向文件末尾追加内容:
```ch
定义(字符串) additional = "追加的内容";
文件追加("example.txt", additional);
```
**完整示例:**
```ch
定义(空类型) 主函数() {
// 写入文件
定义(字符串) data = "Hello, File!";
文件写入("test.txt", data);
// 读取文件
定义(字符串) content;
文件读取("test.txt", content);
控制台输出("读取的内容: " + content);
// 追加内容
文件追加("test.txt", "\n这是追加的内容");
}
```
**布尔类型操作:**
```ch
// 布尔型变量定义
定义(布尔型) isActive = 真; // 真值
定义(布尔型) isEmpty = 假; // 假值
// 布尔运算符
isActive && 假; // 逻辑与:真 && 假 = 假
isActive || 假; // 逻辑或:真 || 假 = 真
!isActive; // 逻辑非:!真 = 假
// 基本运算符
定义(整型) a = 5;
定义(整型) b = 2;
定义(小数) x = 3.0;
定义(小数) y = 2.0;
// 算术运算符
a + b; // 加法:5 + 2 = 7
a - b; // 减法:5 - 2 = 3
a * b; // 乘法:5 * 2 = 10
a / b; // 除法:5 / 2 = 2
a % b; // 取模:5 % 2 = 1
a ^ b; // 乘方:5 ^ 2 = 25
x ^ y; // 小数乘方:3.0 ^ 2.0 = 9.0
x ^ 2; // 混合类型:3.0 ^ 2 = 9.0
// 比较运算返回布尔值
a < b; // 返回 真
a == b; // 返回 假
```
**数组操作:**
```ch
// 一维数组
定义(整型) arr[10];
控制台输出(arr[0]); // 输出数组第一个元素
arr[5] = 100; // 给数组元素赋值
// 动态数组大小(新增功能)
定义(整型) size = 5;
定义(整型) dynamicArr[size]; // 使用变量定义数组大小
定义(整型) n1 = 3, n2 = 4;
定义(整型) exprArr[n1 + n2]; // 使用表达式定义数组大小
// 多维数组(支持1-5维)
定义(整型) matrix[3][4]; // 二维数组 3x4
定义(整型) cube[2][2][2]; // 三维数组 2x2x2
定义(整型) arr5[2][2][2][2][2]; // 五维数组
// 多维动态数组
定义(整型) rows = 2, cols = 3;
定义(整型) dynamicMatrix[rows][cols]; // 多维动态数组
// 多维数组访问和赋值
matrix[1][2] = 42; // 给二维数组元素赋值
cube[0][1][1] = 100; // 给三维数组元素赋值
arr5[1][1][1][1][1] = 999; // 给五维数组元素赋值
// 数组索引可以是变量
定义(整型) i = 3;
定义(整型) j = 2;
matrix[i][j] = 42; // matrix[3][2] = 42
dynamicArr[i] = 42; // 动态数组元素赋值
dynamicMatrix[i][j] = 42; // 多维动态数组元素赋值
```
**结构体操作:**
**结构体定义:**
使用 `定义(结构体)` 关键字定义结构体类型:
**重要:结构体定义必须在主函数外部!**
```ch
// 结构体定义(在主函数外部)
定义(结构体) Person {
整型 age; // 年龄成员
字符串 name; // 姓名成员
小数 score; // 分数成员
};
定义(结构体) Point {
整型 x; // X坐标
整型 y; // Y坐标
字符串 color; // 颜色
};
// 主函数(在主函数外部)
定义(空类型) 主函数() {
// 在主函数内部创建结构体变量和使用结构体
}
```
**结构体变量和成员访问:**
使用 `定义(结构体类型名)` 语法定义结构体变量,结构体变量只能通过以下方式初始化:
1. **无初始化器**:创建一个具有默认值的结构体变量
2. **同类型变量赋值**:从已存在的同类型结构体变量赋值
```ch
// 方式1:无初始化器(创建默认实例)
定义(Person) person1; // 创建默认的Person实例,所有成员使用默认值
定义(Point) point1; // 创建默认的Point实例,所有成员使用默认值
// 方式2:同类型变量赋值
定义(Person) person2 = person1; // 正确:Person 类型赋值给 Person 类型
定义(Point) point2 = point1; // 正确:Point 类型赋值给 Point 类型
// 错误示例:
// 定义(Person) person3 = "Person:age=25;name=张三;score=85.5"; // 错误:不能使用字面量初始化
// 定义(Point) point3 = person1; // 错误:不能将 Person 类型赋值给 Point 类型
// 访问结构体成员
控制台输出("姓名: " + person1.name); // 输出:空字符串(默认值)
控制台输出("年龄: " + person1.age); // 输出:0(默认值)
控制台输出("分数: " + person1.score); // 输出:0.0(默认值)
控制台输出("X坐标: " + point1.x); // 输出:0(默认值)
控制台输出("Y坐标: " + point1.y); // 输出:0(默认值)
控制台输出("颜色: " + point1.color); // 输出:空字符串(默认值)
```
**结构体成员赋值:**
```ch
// 创建结构体变量
定义(Point) point1;
// 直接对结构体成员赋值
point1.x = 100;
point1.y = 200;
point1.color = "红色";
// 访问更新后的成员值
控制台输出("Point: x=" + point1.x + ", y=" + point1.y + ", color=" + point1.color);
```
**结构体变量赋值规则:**
- 结构体变量只能从同类型的变量初始化
- 不能使用字面量(如 "Person:age=25;name=张三")直接初始化结构体变量
- 不同类型的结构体变量之间不能互相赋值
- 结构体变量可以赋值给同类型的其他变量
- 支持直接对结构体成员进行赋值操作
**完整结构体示例:**
```ch
// 定义结构体
定义(结构体) Student {
整型 id;
字符串 name;
小数 gpa;
布尔型 isGraduate;
};
定义(空类型) 主函数() {
// 创建学生对象(使用默认值)
定义(Student) student1; // 创建默认的Student实例
定义(Student) student2; // 创建另一个默认的Student实例
// 结构体变量赋值(相同类型)
定义(Student) student3 = student1;
// 直接对结构体成员赋值
student1.id = 1001;
student1.name = "张三";
student1.gpa = 3.8;
student1.isGraduate = 假;
// 输出学生信息
控制台输出("学生1姓名: " + student1.name); // 输出:张三
控制台输出("学生1ID: " + student1.id); // 输出:1001
控制台输出("学生1GPA: " + student1.gpa); // 输出:3.8
控制台输出("学生3姓名: " + student3.name); // 输出:空字符串(从 student1 赋值)
}
```
### 小数类型
使用 `小数` 关键字定义小数类型变量:
```ch
定义(小数) pi = 3.14;
定义(小数) radius = 5.0;
定义(小数) area = pi * radius * radius;
控制台输出("圆的面积: " + area);
```
### 循环语句
**while循环:**
```ch
定义(整型) i = 0;
当 (i < 5) {
控制台输出("i = " + i);
i = i + 1;
}
```
**for循环:**
```ch
定义(整型) j = 0;
对于 (j = 0; j < 3; j = j + 1) {
控制台输出("j = " + j);
}
```
### 函数重载
解释器支持函数重载,即同名函数可以有不同的参数类型:
```ch
// 定义多个同名函数,参数类型不同
定义(整型) add(定义(整型) a, 定义(整型) b) {
返回 a + b;
}
定义(小数) add(定义(小数) a, 定义(小数) b) {
返回 a + b;
}
定义(字符串) add(定义(字符串) a, 定义(字符串) b) {
返回 a + b;
}
// 调用时会根据参数类型自动选择合适的函数
定义(空类型) 主函数() {
控制台输出(add(10, 20)); // 调用整型版本,输出30
控制台输出(add(3.14, 2.86)); // 调用小数版本,输出6.0
控制台输出(add("Hello", "World")); // 调用字符串版本,输出HelloWorld
}
```
### 函数返回类型检查
所有函数都必须严格遵守返回类型:
```ch
// 正确的返回类型
定义(整型) getInt() {
返回 42; // 正确,返回整型
}
定义(小数) getDouble() {
返回 3.14; // 正确,返回小数
}
定义(布尔型) getBool() {
返回 真; // 正确,返回布尔型
}
定义(空类型) print() {
控制台输出("Hello");
返回; // 正确,空类型函数可以使用返回退出
}
// 错误的返回类型(会导致编译错误)
定义(整型) wrongFunc() {
返回 3.14; // 错误:返回小数,但声明为整型
}
定义(空类型) wrongFunc2() {
返回 42; // 错误:空类型函数不能返回值
}
```
## 中文关键字与 C++ 关键字对照表
| 中文关键字 | C++ 关键字 | 说明 |
|----------|-----------|------|
| 定义 | - | 用于变量和函数定义 |
| 整型 | int | 整数类型 |
| 字符串 | string | 字符串类型 |
| 空类型 | void | 无返回值类型 |
| 主函数 | main | 程序入口函数 |
| 如果 | if | 条件判断 |
| 否则 | else | 条件判断的分支 |
| 否则如果 | else if | 条件判断的中间分支 |
| 控制台输出 | cout | 输出到控制台 |
| 控制台输入 | cin | 从控制台输入 |
| 返回 | return | 函数返回值 |
| 小数 | double | 小数类型 |
| 布尔型 | bool | 布尔类型 |
| 真 | true | 布尔真值 |
| 假 | false | 布尔假值 |
| 当 | while | 循环语句 |
| 对于 | for | 循环语句 |
| 文件读取 | - | 从文件读取内容 |
| 文件写入 | - | 向文件写入内容 |
| 文件追加 | - | 向文件追加内容 |
| 结构体 | struct | 结构体关键字(用于定义(结构体)) |
| 数组 | - | 数组类型关键字 |
| ^ | pow | 乘方运算符 |
| +, -, *, /, % | +, -, *, /, % | 算术运算符 |
| &&, \|\| | &&, \|\| | 逻辑运算符 |
| ==, !=, <, >, <=, >= | ==, !=, <, >, <=, >= | 比较运算符 |
## 运行/解析流程
1. **读取文件**:读取 `.ch` 文件内容
2. **词法分析**:将源代码转换为 Token 序列
3. **语法分析**:构建抽象语法树 (AST)
4. **执行**:遍历 AST 并执行相应的操作
5. **输出结果**:将执行结果输出到控制台
## 示例代码
### 示例 1:Hello World
**文件名:** `examples/hello.ch`
```ch
定义(空类型) 主函数() {
控制台输出("Hello World!");
}
```
**运行结果:**
```
Hello World!
```
### 示例 2:基本运算
**文件名:** `examples/calculator.ch`
```ch
定义(空类型) 主函数() {
定义(整型) a = 10;
定义(整型) b = 20;
定义(整型) sum = a + b;
定义(整型) product = a * b;
控制台输出("a + b = " + sum);
控制台输出("a * b = " + product);
}
```
**运行结果:**
```
a + b = 30
a * b = 200
```
### 示例 3:条件判断
**文件名:** `examples/conditions.ch`
```ch
定义(空类型) 主函数() {
定义(整型) score = 85;
如果 (score >= 90) {
控制台输出("成绩优秀");
} 否则如果 (score >= 80) {
控制台输出("成绩良好");
} 否则如果 (score >= 70) {
控制台输出("成绩中等");
} 否则如果 (score >= 60) {
控制台输出("成绩及格");
} 否则 {
控制台输出("成绩不及格");
}
}
```
**运行结果:**
```
成绩良好
```
### 示例 4:函数重载
**文件名:** `examples/function_overload.ch`
```ch
定义(整型) add(定义(整型) a, 定义(整型) b) {
返回 a + b;
}
定义(小数) add(定义(小数) a, 定义(小数) b) {
返回 a + b;
}
定义(字符串) add(定义(字符串) a, 定义(字符串) b) {
返回 a + b;
}
定义(空类型) 主函数() {
控制台输出(add(10, 20)); // 调用整型版本
控制台输出(add(3.14, 2.86)); // 调用小数版本
控制台输出(add("Hello", "World")); // 调用字符串版本
}
```
**运行结果:**
```
30
6
HelloWorld
```
### 示例 5:结构体操作
**文件名:** `examples/struct_demo.ch`
```ch
定义(结构体) Point {
整型 x;
整型 y;
字符串 color;
};
定义(空类型) 主函数() {
// 创建结构体变量
定义(Point) point1;
// 直接对结构体成员赋值
point1.x = 100;
point1.y = 200;
point1.color = "红色";
// 输出结构体成员
控制台输出("Point: x=" + point1.x + ", y=" + point1.y + ", color=" + point1.color);
}
```
**运行结果:**
```
Point: x=100, y=200, color=红色
```
### 示例 6:数组操作
**文件名:** `examples/array_demo.ch`
```ch
定义(空类型) 主函数() {
// 数组定义和初始化
定义(整型) numbers[5];
定义(整型) i = 0;
// 给数组赋值
对于 (i = 0; i < 5; i = i + 1) {
numbers[i] = (i + 1) * 10;
}
// 输出数组内容
控制台输出("数组内容:");
对于 (i = 0; i < 5; i = i + 1) {
控制台输出("numbers[" + i + "] = " + numbers[i]);
}
// 数组计算
定义(整型) sum = 0;
对于 (i = 0; i < 5; i = i + 1) {
sum = sum + numbers[i];
}
控制台输出("数组总和: " + sum);
}
```
**运行结果:**
```
数组内容:
numbers[0] = 10
numbers[1] = 20
numbers[2] = 30
numbers[3] = 40
numbers[4] = 50
数组总和: 150
```
### 示例 7:文件操作
**文件名:** `examples/file_demo.ch`
```ch
定义(空类型) 主函数() {
// 写入文件
定义(字符串) content = "Hello, File!";
文件写入("test.txt", content);
// 读取文件
定义(字符串) fileContent;
文件读取("test.txt", fileContent);
控制台输出("读取的内容: " + fileContent);
// 追加内容
文件追加("test.txt", "\n这是追加的内容");
}
```
**运行结果:**
```
读取的内容: Hello, File!
```
### 示例 8:作用域限制
**文件名:** `examples/scope_test.ch`
```ch
// 全局作用域:只能定义变量和结构体
定义(整型) globalVar = 100;
定义(结构体) GlobalStruct {
整型 value;
};
定义(空类型) 主函数() {
// 函数内部可以执行各种操作
控制台输出("在函数内部可以执行各种操作");
控制台输出("全局变量值: " + globalVar);
// 函数内定义的变量
定义(整型) localVar = 50;
控制台输出("局部变量值: " + localVar);
// 文件操作(只在函数内允许)
文件写入("test.txt", "这是函数内的操作");
}
```
**注意:** 如果在全局作用域中尝试执行文件读写等操作,会产生错误:
```
在全局作用域中不允许执行此操作,只能定义变量或结构体 在第 X 行
```
## 字符编码支持
**ASCII码表适配:**
- 完全支持ASCII字符(0-127)
- 自动兼容中文字符(128+)
- 支持UTF-8编码环境下的所有字符
**乱码修复实现原理:**
为确保中文关键字、中文输出内容和中文报错信息能正常显示,解释器在启动时会尝试设置中文 locale:
1. 首先尝试设置 `zh_CN.UTF-8` 编码的 locale
2. 如果失败,尝试设置 `Chinese` locale
3. 如果仍然失败,使用默认 locale
4. Windows环境下自动设置控制台代码页为65001(UTF-8)
这样可以保证在不同操作系统环境下(Windows、Linux、macOS)都能正确显示中文。
## 核心功能
1. **中文关键字**:所有关键字全部使用中文,无任何英文关键字
2. **数据类型支持**:
- 基础类型:整型、字符串、小数、布尔型
- 字面量:真、假(布尔型字面量)
- 完整的布尔运算:&&、||、!运算符
3. **变量定义**:支持整型、字符串、小数、布尔型变量的定义与初始化
4. **多维数组支持**:
- 支持1-5维数组,最多5维
- 语法类似C/C++:`定义(整型) arr[3][4][5];`
- 完整的数组定义、初始化、访问和赋值功能
- 支持动态索引:`arr[i][j]` (i,j为变量)
- 数组元素自动初始化为0
5. **函数定义**:支持无返回值和有返回值的函数定义
6. **函数重载**:支持同名函数不同参数类型
7. **函数作用域限制**:全局作用域只允许变量定义和结构体定义
8. **函数返回类型检查**:确保函数返回类型与定义一致
9. **智能类型系统**:
- 整型运算返回整型(如:10 + 3 = 13)
- 浮点数运算返回浮点数(如:3.14 * 2 = 6.28)
- 混合运算支持类型自动转换
10. **布尔逻辑运算**:
- 逻辑与:`&&` 运算符
- 逻辑或:`||` 运算符
- 逻辑非:`!` 运算符
- 比较运算:`<、>、<=、>=、==、!=`,返回布尔值
11. **基本运算**:支持加减乘除、取模、乘方、比较运算、逻辑运算
12. **控制台输入输出**:支持从控制台输入和输出变量值、字符串
13. **文件读写操作**:
- 文件写入:创建或覆盖文件内容
- 文件读取:从文件读取内容到变量
- 文件追加:在文件末尾追加内容
- 支持复杂的表达式作为文件名和内容
14. **流程控制**:if-else if-else条件判断、while/for循环
15. **结构体支持**:
- 结构体定义:使用 `定义(结构体)` 关键字
- 结构体变量:支持结构体类型的变量实例化
- 成员访问:通过 `.` 运算符访问结构体成员
- 成员赋值:支持直接对结构体成员进行赋值操作
- 完整类型支持:整型、字符串、小数、布尔型成员
16. **主函数机制**:以 `主函数()` 作为程序唯一入口
17. **ASCII兼容**:完全支持ASCII码表和中文字符
18. **精确错误定位**:所有错误都包含行号和列号信息
19. **严格错误处理**:移除所有"假设"和"简化处理",提供详细错误信息
## 使用方法
### 编译
#### 方式一:直接使用g++编译
```bash
# 编译chplus解释器
g++ main.cpp src/lexer/lexer.cpp src/parser/parser.cpp src/executor/interpreter.cpp -std=c++17 -o chplus.exe
```
#### 方式二:使用CMake编译(推荐)
```bash
# 创建构建目录
mkdir build && cd build
# 配置项目(Linux/MacOS)
cmake ..
# 配置项目(Windows MinGW)
cmake -G "MinGW Makefiles" ..
# 构建项目
cmake --build .
# 运行程序
./chplus.exe ../examples/hello.ch
```
#### 2. 代码格式化工具
chplus集成了智能代码格式化功能,支持:
**自动格式化(默认):**
- 修复松散格式(如 `定义( 空类型 )主函数( )` → `定义(空类型)主函数()`)
- 标准化缩进和换行
- 中文符号自动转换为英文符号
- 保持语法错误不修改
- 智能换行:`{` 不换行,`}` 必须换行
**命令行选项:**
- `-a` : 自动格式化并覆盖原文件
- `--no-format, -n` : 不自动格式化代码
- `--help, -h` : 显示帮助信息
**格式化效果示例:**
**输入(松散格式):**
```ch
定义( 空类型 )主函数( )
{
控制台输出 ( "Hello World" ) ;
}
```
**输出(标准格式):**
```ch
定义(空类型)主函数(){
控制台输出("Hello World");
}
```
### 运行
```bash
# 标准运行(自动格式化)
./chplus.exe examples/hello.ch
# 不自动格式化运行
./chplus.exe --no-format examples/hello.ch
# 查看帮助
./chplus.exe --help
```
## 错误处理
解释器的所有报错输出均使用中文,所有错误都包含精确的行号信息:
**错误信息格式:**
- 错误类型和具体原因
- 错误位置(行号)
- 详细的错误说明
**示例错误信息:**
```
错误: 变量未定义: x 在第 5 行
错误: 数组未定义: dp 在第 8 行
错误: 除零错误 在第 15 行
错误: 无效的数组索引: abc 在第 20 行
错误: 不支持的运算符: ^ 在第 25 行
错误: 函数未定义: add(整型, 整型) 在第 30 行
错误: 返回类型不匹配: 期望 整型,但实际返回 小数 在第 35 行
错误: 在全局作用域中不允许执行此操作,只能定义变量或结构体 在第 40 行
```
**改进的错误检查:**
- ✅ 变量存在性检查:访问未定义变量会报错
- ✅ 数组边界检查:防止访问不存在的数组元素
- ✅ 类型检查:确保运算类型兼容
- ✅ 除零检查:防止除零运算
- ✅ 语法错误检查:确保代码语法正确
- ✅ 函数重载检查:确保函数参数类型匹配
- ✅ 返回类型检查:确保函数返回类型与定义一致
- ✅ 作用域检查:确保全局作用域只允许定义操作
**严格的错误处理:**
- 移除了所有"假设"和"简化处理"代码
- 添加了完整的类型验证
- 改进了数组操作的错误处理
- 优化了表达式求值的错误检测
- 添加了函数重载的错误处理
- 改进了返回类型检查
## 注意事项
1. 解释器支持完整的数组功能和智能类型系统
2. 变量类型支持整型、字符串、小数、布尔型类型
3. 所有错误都有精确的行号定位
4. 建议使用 UTF-8 编码保存 `.ch` 文件,以避免字符编码问题
5. 结构体变量只能通过两种方式初始化:无初始化器(创建默认实例)或同类型变量赋值
6. 支持直接对结构体成员进行赋值操作
7. **函数作用域限制**:全局作用域(主函数外部)只能定义变量和结构体,不允许执行其他操作
8. **函数重载**:同名函数必须有不同的参数类型,调用时会自动选择合适的函数
9. **返回类型检查**:所有函数都必须严格遵守返回类型,不匹配会报错
10. **空类型函数**:可以使用返回语句退出函数,但不能返回值
## 未来计划
1. 增加更多数据类型支持(如枚举类型等)
2. 完善函数参数列表的解析
3. 增加更多流程控制语句(如 switch 语句等)
4. 增加调试功能和断点支持
5. 优化性能,支持更大规模的程序
## 许可证
本项目采用 **GNU AGPL v3.0 + Commons Clause 1.0** 协议授权,核心规则如下:
1. 🆓 个人非商业用途可自由使用、修改、分发
2. 🚫 禁止任何形式的商业使用(包括出售、出租、作为商业产品组件等)
3. 🔧 修改后的衍生作品必须:
- 保留原项目版权和许可证信息
- 以相同协议开源并附带完整源代码
- 明确标注衍生作品与原项目的差异,并提供原项目源库链接
4. 📄 完整许可证内容请查看项目根目录下的 `LICENSE` 文件
原项目源库:[https://github.com/abcdefgjh-li/chplus] |
免费评分
-
查看全部评分
|