# rust-lexer **Repository Path**: RaidenLumine/rust-lexer ## Basic Information - **Project Name**: rust-lexer - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-15 - **Last Updated**: 2026-10-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Rust 单词拼装分类器 编译原理实验一。用 C++ 写的 Rust 词法分析器,外加一个 Qt 图形界面。 做两件事: 1. 把 Rust 源代码切成一个个**记号**,并判定每个记号属于哪一类(关键字、标识符、各类字面量、注释、分隔符、操作符……)。 2. 用对话框打开源文件、用对话框列出所有记号及其分类。 --- ## 目录结构 ``` src/ 词法分析核心库。不依赖 Qt,命令行版和图形界面共用这一份 gui/ Qt Widgets 界面 test/ 测试程序与测试用例 cmake/ CMake 工具链文件(交叉编译用) scripts/ 交叉编译环境的安装脚本 docs/ 作业要求与实验报告格式 ``` --- ## 依赖 | 工具 | 备注 | |---|---| | 编译器 | 支持 C++20 的 GCC 11+ / MSVC 19.3+(交叉编译界面时用 llvm-mingw 的 clang) | | 构建工具 | CMake 3.16+(用 Makefile 的话只要 GNU make) | | 图形界面 | Qt 6(Widgets 模块)。不装也能编命令行版 | | 交叉编译 | llvm-mingw 20231128 + Qt 6.11.1 的 Windows 包,见下文 | --- ## 快速开始 ### 命令行版 ```bash make # 编译 make run # 编译并跑测试 ``` 跑完应当看到 `通过 54 / 54`。 ### Windows 端(MSVC) Windows 下 `make` 默认用 Visual Studio 的 `cl.exe`,并且会自己 `call` `vcvars64.bat`,所以在普通 PowerShell / VS Code 终端里直接敲就行,不必先开 「Developer Command Prompt」,当然开了也可以,那样连 vcvars 都省了: ```powershell make make run ``` `vcvars64.bat` 的位置靠 VS 安装器自带的 `vswhere` 找,装了多个版本时取最新的 那个。它找不到、或者你想用别的编译器时,显式指一下: ```powershell make VCVARS="C:\Program Files\Microsoft Visual Studio\18\Community\VC\Auxiliary\Build\vcvars64.bat" make TOOLCHAIN=mingw MINGW_CXX=C:\mingw64\bin\g++.exe ``` MSVC 编出来的中间文件是 `.obj`(GCC/MinGW 是 `.o`),两者各占一个名字,换工具链 不会捡到上一次的旧对象文件。 ### 图形界面 ```bash make qt-gui-run ``` Linux 上发行版装的 Qt 一般能自动找到。装了 Qt 官方安装器、又不在默认搜索 路径的,显式指一下,例如: ```bash make qt-gui-run QT_PREFIX=/opt/Qt/6.11.1/gcc_64 ``` Windows 上会自己到 `msvc*_64`(配 MSVC)或 `mingw*_64`(配 MinGW)里找一个装好的 Qt,`make qt-gui-run` 直接把界面起起来——运行前它会 把 Qt 的 `bin` 目录临时加进 `PATH`,所以不用自己配环境变量。装了多个 Qt 版本时用 `QT_PREFIX` 指定最稳: ```powershell make qt-gui-run QT_PREFIX=C:\Qt\6.11.2\msvc2022_64 ``` ### 直接用 CMake 这里也提供 cmake 原生命令: ```bash cmake -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --parallel ctest --test-dir build --output-on-failure ``` Windows 上 CMake 默认用 Visual Studio 生成器,它是多配置的,编译和跑测试 要带上配置名: ```powershell cmake -B build -DCMAKE_PREFIX_PATH=C:\Qt\6.11.2\msvc2022_64 cmake --build build --config Release --parallel ctest --test-dir build -C Release --output-on-failure ``` 多配置生成器不用、也不该在 configure 时挑构建类型:`--config` 给什么,运行库和 优化级别就跟着变(Debug 是 `/MDd /Od`,发布是 `/MD /O2`)。所以 `--config Debug` 编出来的就是真正的调试版,不必再改 configure 的参数。 产物统一在 `build/bin/`(两种生成器都是这个路径)。找不到 Qt 时会跳过图形 界面、只编核心库和测试,不会因此报错。 --- ## 命令一览 `make` 目标: | 命令 | 作用 | |---|---| | `make` | 编译本机可执行文件 | | `make run` | 编译并运行测试 | | `make debug` | 带 `-g -O0` 的调试版 | | `make release` | 优化版(默认) | | `make clean` | 删掉整个 `build/` | | `make help` | 打印这份清单和当前配置 | | `make compile-linux` | 产出 Linux 可执行文件 | | `make compile-win` | 产出 Windows exe(Linux 上是交叉编译,需要 MinGW-w64;Windows 上按 `TOOLCHAIN` 走 MSVC 或 MinGW) | | `make compile-win GUI=1` | 同上,但换成 GUI 子系统(MinGW 是 `-mwindows`),双击不弹控制台 | | `make qt-gui` | 编译出带图形界面的程序 | | `make qt-gui-run` | 编译好并直接运行界面(Windows 上会先把 Qt 的 `bin` 加进 `PATH`) | | `make qt-gui-win` | 在 Linux 上交叉编译出 Windows 界面 exe(Windows 上等同 `qt-gui`) | | `make deploy-win` | 凑出自包含发布目录:Windows 上用 Qt 的 `windeployqt`,Linux 上手工列 DLL | 常用变量(放在命令后面,如 `make run BUILD_TYPE=debug`): | 变量 | 默认值 | 说明 | |---|---|---| | `BUILD_TYPE` | `release` | `release` 或 `debug` | | `TEST` | `test_lexer` | 换一个测试程序(`test/` 下每个 `.cpp` 都是一支) | | `GUI` | `0` | Windows 下设成 `1` 走 GUI 子系统 | | `TOOLCHAIN` | `auto` | `auto` / `msvc` / `mingw`。Windows 本机编译默认走 MSVC | | `VCVARS` | 自动探测 | 自己指定 `vcvars64.bat` 的位置 | | `MINGW_CXX` | `x86_64-w64-mingw32-g++` | 换交叉编译器(`TOOLCHAIN=mingw` 时用) | | `QT_PREFIX` | 自动探测 | 本机 Qt 的位置 | | `QT_WIN_PREFIX` | `~/.cache/qt-cross/Qt/6.11.1/llvm_mingw` | 目标平台的 Qt | | `QT_WIN_EXTRA_DLLS` | `0` | 设成 `1` 时发布目录里也带上 d3dcompiler / opengl32sw | --- ## 图形界面怎么用 - **输入代码**:左边「源代码」区可以直接敲、直接粘。停手约 0.25 秒后自动重新分析,右边的表和底下的诊断跟着更新,不需要按任何按钮。 - **打开文件**:「文件 → 打开」选一个 `.rs`,或者把文件直接拖进窗口。拖到左边代码区上也是打开文件,不会变成一行路径。 - **新建**:「文件 → 新建」清空重来。 - **记号表**:右边表格五列——序号、词素、类别、行、列。 - **词法诊断**:底下列出出错的记号,含行号、列号和原因。 - **查看分类结果**:「文件 → 查看分类结果」弹出对话框,按 `词素 : 类别` 一行一个铺开,可全选复制或另存为文本文件。这是作业要求的那个对话框。 - **另存结果**:「文件 → 另存结果」直接把上面那份文本存成文件。 命令行也支持带一个文件名启动: ```bash build/qt-gui/bin/rust_lexer_gui 某个文件.rs ``` --- ## 交叉编译到 Windows 在 Linux 上编译出 Windows 的图形界面 exe。整条链的版本必须严格咬合,所以用脚本装,不要自己拼。 (在 Windows 上不需要交叉编译:直接 `make qt-gui-run`,要发布目录就 `make deploy-win`。) ```bash scripts/setup-qt-cross.sh # 装 llvm-mingw 和 Windows 版 Qt make deploy-win QT_PREFIX=/opt/Qt/6.11.1/gcc_64 ``` 产物在 `build/qt-gui-win-dist/`,是个自包含的目录:exe、Qt 的 DLL、平台插件、C++ 运行时全在里面。整个目录拷到 Windows 上双击 exe 就能用,目标机器不需要装 Qt。 >几个要点: > > - **不能用系统发行版的 `g++-mingw-w64`**。Ubuntu 的是 GCC / win32 线程 / msvcrt,而 Qt 的 Windows 包是 llvm-mingw / posix 线程 / UCRT,ABI 不匹配,链接阶段必炸。这是配置改不回来的,必须换编译器。 > - **宿主 Qt 的版本号要和目标 Qt 完全一致**。交叉编译时 `moc`/`rcc`/`uic` 得在 Linux 本机跑,而 Windows 包里带的是 `.exe`。系统自带的 Qt 版本对不上就顶不了(脚本会检查并报错)。 > - **`libc++.dll` 必须跟着 exe 走**。llvm-mingw 默认动态链 libc++,exe 旁边没有它就起不来,报 `0xc0000135`。CMake 会自动拷,`deploy-win` 也会再确认一遍。 > - **发布目录里没有 d3dcompiler_47.dll 和 opengl32sw.dll**,这是有意为之:那两个是 Qt Quick 的 D3D / OpenGL 后端要的,本程序是纯 QtWidgets,走光栅绘制,用不上。带上它们目录会从 31M 涨到 55M。以后要是加了`QOpenGLWidget` 之类的东西,`make deploy-win QT_WIN_EXTRA_DLLS=1`。 `scripts/setup-qt-cross.sh` 会把东西装在 `~/.cache/qt-cross/`,不进仓库。国内直连 GitHub Releases 和 download.qt.io 都很慢,脚本默认走[ghfast.top](https://ghfast.top/) 反代和清华 TUNA 镜像,前者失败会自动回退直连。可以用环境变量换源: ```bash GH_MIRROR= QT_MIRROR=https://mirrors.ustc.edu.cn/qt scripts/setup-qt-cross.sh ``` --- ## 测试数据 `test/` 下每个 `.cpp` 是一支独立的测试程序,共用的框架和用例在 `.h` 里。 | 文件 | 覆盖 | |---|---| | `cases_keywords.h` | 关键字 | | `cases_literals.h` | 各类整数字面量、浮点数、字符、字符串、字节串、原生字符串 | | `cases_symbols.h` | 分隔符与操作符 | | `cases_comments.h` | 行注释、块注释(含嵌套) | | `cases_errors.h` | 各类词法错误 | | `golden.h` | 作业文档里的样例,逐 token 比对输出 | `golden.h` 是回归网:它把样例源码跑一遍,把结果和文档里给的输出逐行对齐。动了词法器之后 `make run` 必须还是 54/54。 --- ## 记号类别 关键字、标识符、字面量(二进制/八进制/十进制/十六进制整数、浮点数、布尔)、字符字面量、字符串字面量(含原生)、字节字面量、字节串字面量(含原生)、生命周期、宏调用名、注释、分隔符、操作符、赋值操作符、非法记号。 具体名字见 `src/TokenType.cpp` 里的 `tokenTypeName()`。 --- ## 已知取舍 - **词法器把任何 `>= 0x80` 的字节都当作标识符字符**,没有查 Unicode 的 XID 表。绝大多数情况下这是对的(Rust 标识符本来就能用中文),代价是非法字符有时不会被报成错误,而是拼进标识符里。带 UTF-8 BOM 的文件会因此多出一个假标识符,所以界面在读文件时会先把 BOM 剥掉。 - **`@`、`$`、`?`、`#` 一律算操作符**,没有区分它们在不同上下文里的含义,因为那是语法分析的事,词法阶段只认字符本身。