Files
stgsharp/future/ngra-regex-ir.md
T
2026-06-22 18:18:16 +08:00

75 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 适用于NGRA字符串正则的IR形式
## 两个指针
1. 活动指针,记录当前的搜索位置,下文“不更新活动指针”的意思是算计结束后自行对活动指针进行复位
2. 锚点指针,记录一个区间的开始位置
## 检查点
检查点是锚点指针的一种形式,以栈形态存储,创建检查点时,上一个检查点自动压栈,并用当前检查点替换为当前的锚点指针
## 符号区
使用DEFINE指令定义的符号定义在符号区中,符号的类型通过第一次赋值确定,源生成模式下,可以通过第一个赋值指令推导其类型
## HIR算子
1. 搜索算子(SEARCH %str; SEARCH %unicode),向后搜索确定长度序列或者满足规则的字符集,更新活动指针,不更新锚点指针,搜索结果保存在全局上下文中
2. 搜索算子(SEARCH %set_expression),向后匹配一个满足字符集要求的字符,更新活动指针,不更新锚点指针,搜索结果保存在全局上下文中
3. 条件指令(CONDITION %cmd_true %cmd_fail),比较前一条SEARCH指令是否成功,并指定跳转到指定的位置,如果某种条件不需要跳转,可以写1。如果想要将fail向上级继续抛出,可以%cmd_fail写0.
4. 计数指令(COUNT %min %max %is_greedy %cmd),重复执行指令cmd,直到满足参数配置的数量为止
5. 快速序列计数指令(COUNT_SEQ %min %max %is_greedy %seq),快速搜索一个确定性序列,直到满足参数配置的数量为止
6. 快速字符集计数指令(COUNT_SET %min %max %is_greedy %set),快速搜索一个字符集,直到满足参数配置的数量为止
7. 尝试(TRY %count),对自身向后的一段内容在新的匹配栈层级中进行运行,被分层的指令数量由COUNT指令确定
8. 弹出(POP %is_success),提前终止一个try块,并用is_success表示弹出行为视为匹配成功还是失败
9. 打包指令(PACK %is_success %name),检查上一条语句的结果,将匹配结果打包并记录为指定的名字。如果名字为空,则使用默认的序号进行索引
## 优化策略
应当注意的是,将HIT进行进一步优化或者展开的目的:
1. 尽可能降低源生成或者运行时执行中,对多指令上下文的依赖,尽可能保证每一个IR可以单独输出最佳的代码
2. 减少多余的结构,使得一行指令尽可能处理多的数据
### 语义改写优化
1. 计数器展开
建议在lower做
对于形如a+b或者a{2,4}b的正则表达式,可以优化为a*(ab|b)和a{2,3}(ab|b)的写法
2. 确定性计数展开
建议在lower做
对于形如a{m,n}的正则表达式,将其展开为a{m}a{0,n-m}的形式
3. charset合并
建议在ast-opt做
对于形如[ abc ]|[ def ]的表达式,将其合并为[ abcdef ]
4. charset展开
在lower做
对于形如abc[ de ]的表达式,如果字符集容量不超过4,可以站卡为(abcd|abce)形式
### 匹配策略改变
1. 长度预测
在source-gen阶段做
对于一个正则表达式,可以计算其所需的最小长度,可以在开始的时候提前进行比较
2. .*优化
在lower阶段做
对于COUNT_SET min=0 max=-1 "."指令,也就是.*操作,将后续指令从match转为find
3. [ set ]*优化
在source-gen阶段做
对于其他的COUNT_SET min=0 max=-1 "???"指令,使用IndexOf,IndexOfAnyExcept等进行优化
4. 首字母检查
**这个不好做,因为IR直接把ALT打碎成if-else串了**
对于(abc|defg|xyz)表达式,可以检查其首字母
### C# span opt trick
1. Span.StartWith
2. [ 0-9 ]展开为IndexOf("0123456789")