You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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(标记树)匹配范围的同时,同时覆盖整数字面量与具名函数名两类命令;如果重复匹配部分无法同时兼容两类命令,就需要编写数量极多的匹配分支。

待解答问题

  1. 如何修改$(!$vals:tt)+匹配规则,使其对感叹号位于命令左侧/右侧的场景都能正常匹配?
  2. 是否存在方案可以避免为递归分支、基准分支分别编写4个匹配分支(即覆盖感叹号在左/在右、literal/ident四种组合),比如是否可以将空分支作为基准分支减少分支数量?
  3. 是否可以调整递归顺序,实现指令的尾部追加而非头部插入?

内容的提问来源于stack exchange,提问作者Arthur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 15:18:24