Rust递归声明宏编写:适配任意位置感叹号的指令匹配问题
Deque 语言 Rust 解释器声明宏实现问题
背景说明
我为名为 Deque 的小众深奥编程语言(esolang)编写了 Rust 实现的解释器,这里不展开讲解语言运行逻辑,仅明确其基础语法规则:
- 程序由空格分隔的多条指令组成
- 每条指令由命令与感叹号构成,二者顺序无限制
- 命令支持两类:待入栈的整数字面量、预定义的具名调用函数
合法程序示例:
3! !5 !2 sub! !add
现有功能与实现目标
当前解释器核心功能已运行正常:
- 通过
let s = Script::new("3! !5 !2 sub! !add")即可构造程序实例:方法会将传入字符串拆分为独立指令,逐条解析后生成Vec<Instruction>类型的指令集合 - 调用
s.run()会消耗实例并返回程序运行结果
我希望编写一个声明宏简化调用(同时作为声明宏编写练习),目标是支持let mut s = script!(3! !5 !2 sub! !add)的调用形式,必须通过递归方式构造程序实例(我知晓可直接用stringify!将宏内所有标记转为字符串传入Script::new(),但该实现方式达不到练习目的)。
为适配递归逻辑,我额外实现了Script::prepend()方法,用于向指令队列头部插入指令——如果尝试向尾部追加指令,会立刻因标记顺序问题产生解析歧义。
当前实现与遇到的问题
目前已完成的宏代码如下:
macro_rules! script { ($val:literal !) => { Script::new(format!("{}!", $val)) }; ($cmd:ident !) => { Script::new(format!("{}!", stringify!($cmd))) }; (!$val:literal) => { Script::new(format!("!{}", $val)) }; (!$cmd:ident) => { Script::new(format!("!{}", stringify!($cmd))) }; (!$val:literal $(!$vals:tt)+) => { script!($(!$vals)+).prepend(&format!("!{}", $val)[..]) }; () => { Script::new("") }; }
该实现对单指令程序支持良好,但无法正确处理多指令程序。目前仅实现了感叹号全部位于指令左侧场景的递归分支,距离覆盖全场景仍有差距。我尝试过多种修改$(!$vals:tt)+匹配规则的方案,均无法正常工作:
- 尝试通过
$($(!)?$vals:tt$(!))+实现感叹号左右位置的可选匹配,会触发解析歧义问题 - 使用
(!$val:literal $($vals:tt)+)作为匹配分支时,无法解析script!(!5 !6)这类输入,会卡在6旁边的感叹号位置 - 去掉重复标记直接使用
(!$val:literal $vals:tt)匹配,则会卡在字面量6的位置
核心卡点为:无法在收紧tt(标记树)匹配范围的同时,同时覆盖整数字面量与具名函数名两类命令;如果重复匹配部分无法同时兼容两类命令,就需要编写数量极多的匹配分支。
待解答问题
- 如何修改
$(!$vals:tt)+匹配规则,使其对感叹号位于命令左侧/右侧的场景都能正常匹配? - 是否存在方案可以避免为递归分支、基准分支分别编写4个匹配分支(即覆盖感叹号在左/在右、literal/ident四种组合),比如是否可以将空分支作为基准分支减少分支数量?
- 是否可以调整递归顺序,实现指令的尾部追加而非头部插入?
内容的提问来源于stack exchange,提问作者Arthur
相关产品推荐
相关产品推荐

