这是一篇关于在 Rust 中使用logos
crate 编写高效词法分析器的实验文章,主要内容如下:
logos
的目标:logos
的项目有两个主要目标,一是使创建词法分析器变得容易,以便可以专注于更复杂的问题;二是使生成的词法分析器比手动编写的任何东西都快。- 状态机方法:许多词法分析器生成器如
logos
将令牌规范编译为跳转表驱动的状态机。每个令牌变体都表示为一个状态,每个状态都定义了对所有可能扫描字符的可行子集的转换。对于 ASCII 输入,可以让每个状态定义每个可能字符的完整跳转表,并使用原始字节作为状态转换矩阵的查找索引。对于完整的 UTF-8 输入,可能需要调度到更昂贵的分支函数。 - 起始点:作者已经有一个基本的词法分析器,在现代编译器中,词法分析通常占用最少的时间,因此在实现中优先考虑简单性而不是性能。对于关键字匹配,使用了完美哈希函数。
性能测试与优化:
- 在 Apple M1 系统上,
logos
比作者的朴素实现快近两倍,但在 x86_64 上则较慢,推测这是由于推测执行架构的差异。 - 关键字匹配使用完美哈希函数,避免比较所有关键字。
- 内联所有函数可获得 30%的速度提升,去除窥视逻辑和克隆文本字段后,速度仅比
logos
慢 25%。 - 利用大多数源代码实际上是 ASCII 的事实进行优化,类似编译器向量化循环的方式,但要注意与自动向量化的兼容性。
- 使用 SIMD 指令加速快乐路径,通过加载 16 个连续字节到 128 位 SIMD 寄存器进行表查找,但对于多字符令牌仍存在问题。
- 为关键字匹配掩码创建查找表,速度提高了 5 - 10%。
- 使基准测试数据更现实,包括从 Oxide 的 Hubris 内核中获取片段,允许标识符中包含下划线等,但相对改进不如之前明显。
- 在 Apple M1 系统上,
- 结论:通过积极内联和展开,作者的实现在纯吞吐量方面至少比
logos
快 20%,但在解析代码中词法分析器调用交错时的性能尚不清楚。
总体而言,文章通过各种优化手段对词法分析器进行了实验和改进,展示了不同优化方法对性能的影响。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。