# icc_script **Repository Path**: jiang-xiaojian/icc_script ## Basic Information - **Project Name**: icc_script - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-12-20 - **Last Updated**: 2026-01-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # icc_script(迷你 C 子集解释器) 这是一个用 C 实现的迷你 C 子集解释器工程:包含 lexer -> parser -> AST -> evaluator,并提供少量 builtin(内建函数)。 ## 项目结构与层级(图) 执行流水线(解释器内部层级): ``` 源代码字符串 | v Lexer -> Token 流 | v Parser -> AST(语法树) | v Eval -> 运行结果 / 输出(printf 等) ``` 目录层级(代码组织): ``` icc_script/ main.c # 最小示例入口:读文件 -> icc_run_script Makefile # MinGW 构建脚本 README.md # 项目说明 script.icc # 自测脚本(覆盖语言特性) inc/ # 对外头文件(API/数据结构定义) src/ # 实现(lexer/parser/ast/eval/modules) ``` 从“把解释器当库用”的角度: ``` main.c -> main_read_file_to_string() -> icc_run_script(source, len) # inc/icc_run.h + src/icc_run.c -> lexer/parser/ast/eval/modules ``` ## 解释器能力(语言特性) ### 关键字 / 类型 - 标量类型:`int32_t`、`uint32_t`、`uint8_t`、`char`(语义等价于 `uint8_t`) - 控制流:`if`、`else`、`while`、`break` ### 语句(Statements) - 变量声明(标量): - `int32_t a = 1;` - `uint32_t b = 4000000000;` - `char ch = 65;` - 变量声明(数组): - 定长数组:`uint32_t a[4] = {1, 2, 3};` - 另一种数组字面量初始化:`uint8_t a2[3] = [9, 8, 7];` - 字符串初始化(语法糖):`char s[] = "abc";`(自动补 `\0`) - 赋值语句: - 标量赋值:`a = a + 1;` - 数组下标赋值:`a1[1] = 99;` - 表达式语句:`printf("%d\n", 123);` - 语句块:`{ stmt* }` 补充:`else if (...) { ... }` 语法可用(`else` 后面允许直接跟一条 `if` 语句)。 ### 表达式(Expressions) - 整数/标识符 - 括号:`(expr)` - 一元:`!expr` - 二元算术:`+ - * / %` - 比较:`== != < <= > >=` - 逻辑:`&& ||`(支持短路) - 函数调用:`ident(arg1, arg2, ...)` - 数组下标:`arr[index]` - 字符串字面量:`"..."`(作为 `printf` 的 format 或用于 `char[]` 初始化) ### 运行时语义/限制 - 变量表是全局线性表:块 `{}` 不引入新作用域;同名变量会被覆盖。 - `break` 仅允许在 `while` 内;在循环外使用会报 runtime error。 - 数组访问包含运行时越界检查。 ## 内建函数(Builtins / Modules) 解释器运行前会加载内建模块(见 `src/icc_module.c`): ### 内建函数特性(调用约定) - **参数求值**:调用表达式 `foo(a, b + 1)` 会先把每个实参表达式求值,再把求值后的运行时值数组 `argv[]` 传入 builtin。 - **运行时类型**:builtin 可接收的值类型包括: - 数值:`int32_t / uint32_t / uint8_t` - 字符串:字符串切片(来自脚本字符串字面量) - 数组:数组视图(`elem_type + data + len`) - **所有权/可变性**: - 字符串与数组的底层内存由解释器管理;builtin **不应 free**。 - 数组参数以“视图”形式传入,builtin 可以修改数组 `data`(例如 `can_transfer` 修改 `recv`),修改会反映到脚本后续读取。 - **错误处理**:builtin 通常会做 argc/类型检查;出错时通过 `icc_eval_set_error(..., line, col)` 报 runtime error(解释器遵循“first-error wins”,只记录第一个错误)。 - **重名覆盖**:同名 builtin 后注册会覆盖先注册;因此模块加载顺序会影响最终生效实现。 - `printf(format, ...)` - 支持:`%d %i %u %x %X %c %s %%` - 支持 flags/width/precision(如 `%08d`、`%.4x`),但不支持 length modifier(如 `%ld`、`%llu`) - `%s` 支持字符串字面量与 `char/uint8_t` 数组(按 C-string 打印,遇到 `0` 结束或到数组长度) - format 与 `%s` 参数会做基础转义解码:`\n \r \t \\ \"`(其它 `\X` 形式按原样输出 `X`) - 返回值:打印的字符数(`int32_t`) - `add(a, b)`:两个数值参数(`i32/u32/u8`),返回和 - 提升规则:只要任一参数是 `u32`,就按 `u32` 相加并返回 `u32`;否则按 `i32` 相加并返回 `i32` - `mdelay(ms)`:延时指定毫秒数 - 参数:数值类型(`i32/u32/u8`),`i32` 必须非负 - 返回值:`u32`,等于传入的 `ms` - `can_transfer(send, recv, n)`:复制 `uint8_t` 数组并返回复制长度 - 语义:拷贝 `n` 字节到 `recv`(要求 `n <= send.len` 且 `n <= recv.len`),并返回实际拷贝字节数(`u32`) - 参数要求:`send/recv` 都必须是 `uint8_t` 数组;允许零长度数组 ## 文件说明(逐个文件/模块) 根目录: - `main.c`:最小示例入口,只负责读取脚本并调用 `icc_run_script()`。 - `Makefile`:Windows + MinGW 构建脚本,输出到 `output/`。 - `script.icc`:自测脚本,覆盖关键字、数组、控制流、builtin,并输出 PASS/FAIL。 - `README.md`:项目文档。 头文件(inc/): - `inc/icc.h`:聚合头,一次性包含解释器对外 API(示例代码可直接 include 这个)。 - `inc/icc_port.h`:平台抽象层(内存、输出、文件 I/O、errno/strerror 等封装)。 - `inc/icc_run.h`:库式运行入口:`icc_run_script(const char* script, size_t len)`。 - `inc/icc_lexer.h`:lexer 对外结构与 token 定义。 - `inc/icc_parser.h`:parser 对外结构与 parse 接口。 - `inc/icc_ast.h`:AST 数据结构与构造/释放/打印接口。 - `inc/icc_eval.h`:解释执行器(eval)对外结构与运行接口。 - `inc/icc_eval_builtins.h`:builtin 的声明/辅助(与 eval 协作)。 - `inc/icc_module.h`:内建模块加载总入口(注册 printf/add/can_transfer 等)。 - `inc/icc_module_printf.h`:printf 模块声明。 - `inc/icc_module_math.h`:math 模块声明(如 add)。 - `inc/icc_module_can_transfer.h`:can_transfer 模块声明。 实现(src/): - `src/icc_run.c`:`icc_run_script` 的实现:parse+run 并保证释放。 - `src/icc_lexer.c`:词法分析实现(源码 -> token)。 - `src/icc_parser.c`:语法分析实现(token -> AST)。 - `src/icc_ast.c`:AST 工具实现(创建/打印/释放)。 - `src/icc_eval.c`:解释器执行引擎(执行语句/表达式、环境/数组/控制流)。 - `src/icc_eval_builtins.c`:builtin 调用桥接与参数/类型检查等。 - `src/icc_module.c`:builtin 模块注册与加载(`icc_module_load_all`)。 - `src/icc_module_printf.c`:printf 模块实现(格式化输出、%s 支持 char/u8 数组)。 - `src/icc_module_math.c`:math 模块实现。 - `src/icc_module_can_transfer.c`:can_transfer 模块实现。 ## 移植说明(Portability) - 平台/运行库相关接口集中在 `inc/icc_port.h`(内存、输出、文件 I/O 等封装)。 - 目前输出侧按尽量只依赖 printf的约束实现;如果目标平台连 `printf` 都没有,建议把 `ICC_PRINTF` 换成串口/日志回调。 ## 命令行用法(CLI) 可执行文件:`output/icc_script.exe` 当前 `main` 仅保留“运行脚本”的最小示例入口: - 运行默认脚本(默认 `script.icc`): - `output\icc_script.exe` - 运行指定脚本: - `output\icc_script.exe your.icc` - 兼容写法(等价于上面两种): - `output\icc_script.exe --run your.icc` ## 示例脚本 仓库自带 `script.icc`,覆盖全部关键字与主要语义分支,并输出 PASS/FAIL 报告。 运行示例: ```powershell mingw32-make clean mingw32-make .\output\icc_script.exe --run script.icc ``` ## 构建(Windows / MinGW) 在 Windows(PowerShell)下: ```powershell mingw32-make clean mingw32-make ``` 产物:`output/icc_script.exe` > 当前 Makefile 偏向 Windows/MinGW;移植到 Linux/macOS 通常需要调整 Makefile 的 shell/路径/清理命令。 ## 资源占用(粗略数据) 以下数据来自 Windows + MinGW 构建的 `output/icc_script.exe`(仅供估算,具体会随编译器/优化/脚本内容变化): - 可执行文件磁盘大小:约 **197,578 bytes**(≈ 193 KB) - 段大小(GNU `size`): - `text=62,552`、`data=176`、`bss=384`,合计 `dec=63,112`(≈ 61.6 KB) - 若类比 MCU: - ROM(Flash) 近似:`text + data ≈ 62,728 bytes` - 静态 RAM 近似:`data + bss ≈ 560 bytes`