所以我有以下宏代码我正在尝试调试.我是从Rust Book的"The Deep end"一节中读到的.我重命名宏中的变量,以更密切地关注这篇文章.
我的目标是让程序打印出BCT程序的每一行.我很清楚这是编译器很重.
rustc给我的唯一错误是:
user@debian:~/rust/macros$ rustc --pretty expanded src/main.rs -Z unstable-options > src/main.precomp.rs
src/main.rs:151:34: 151:35 error: no rules expected the token `0`
src/main.rs:151 bct!(0, 1, 1, 1, 0, 0, 0; 1, 0);
Run Code Online (Sandbox Code Playgroud)
我可以采取什么步骤,以找出其中的宏观问题是从哪里来的?
这是我的代码:
fn main() {
{
// "Bitwise Cyclic Tag" automation through macros
macro_rules! bct {
// cmd 0: 0 ... => ...
(0, $($program:tt),* ; $_head:tt)
=> (bct_p!($($program),*, 0 ; ));
(0, $($program:tt),* ; $_head:tt, $($tail:tt),*)
=> (bct_p!($($program),*, 0 ; $($tail),*));
// cmd 1x: 1 ... => 1 ... x
(1, $x:tt, $($program:tt),* ; 1)
=> (bct_p!($($program),*, 1, $x ; 1, $x));
(1, $x:tt, $($program:tt),* ; 1, $($tail:tt),*)
=> (bct_p!($($program),*, 1, $x ; 1, $($tail),*, $x));
// cmd 1x: 0 ... => 0 ...
(1, $x:tt, $($program:tt),* ; $($tail:tt),*)
=> (bct_p!($($program),*, 1, $x ; $($tail),*));
// halt on empty data string
( $($program:tt),* ; )
=> (());
}
macro_rules! print_bct {
($x:tt ; )
=> (print!("{}", stringify!($x)));
( ; $d:tt)
=> (print!("{}", stringify!($d)));
($x:tt, $($program:tt),* ; )
=> {
print!("{}", stringify!($x));
print_bct!($program ;);
};
($x:tt, $($program:tt),* ; $($data:tt),*)
=> {
print!("{}", stringify!($x));
print_bct!($program ; $data);
};
( ; $d:tt, $($data:tt),*)
=> {
print!("{}", stringify!($d));
print_bct!( ; $data);
};
}
macro_rules! bct_p {
($($program:tt),* ; )
=> {
print_bct!($($program:tt),* ; );
println!("");
bct!($($program),* ; );
};
($($program:tt),* ; $(data:tt),*)
=> {
print_bct!($($program),* ; $($data),*);
println!("");
bct!($($program),* ; $($data),*);
};
}
// the compiler is going to hate me...
bct!(0, 1, 1, 1, 0, 0, 0; 1, 0);
}
Run Code Online (Sandbox Code Playgroud)
huo*_*uon 20
有两种主要方法可以调试无法扩展的宏:
trace_macros! 和log_syntax!(注意:两者都是特征门控,在同名的功能下,因此需要夜间编译器才能工作,这multirust使得在这种工作的版本之间切换变得容易.)
trace_macros!(...)采用一个布尔参数来打开或关闭宏跟踪(即它是有状态的),如果它处于打开状态,编译器将在扩展时使用其参数打印每个宏调用.通常只想trace_macros!(true);在箱子的顶部抛出一个调用,例如,如果将以下内容添加到代码的顶部:
#![feature(trace_macros)]
trace_macros!(true);
Run Code Online (Sandbox Code Playgroud)
然后输出看起来像:
bct! { 0 , 1 , 1 , 1 , 0 , 0 , 0 ; 1 , 0 }
bct_p! { 1 , 1 , 1 , 0 , 0 , 0 , 0 ; 0 }
<anon>:68:34: 68:35 error: no rules expected the token `0`
<anon>:68 bct!(0, 1, 1, 1, 0, 0, 0; 1, 0);
^
playpen: application terminated with error code 101
Run Code Online (Sandbox Code Playgroud)
希望能够缩小问题的范围:bct_p!呼叫在某种程度上是无效的.仔细观察它会发现问题,第二臂的左侧bct_p使用data:tt时应该使用$data:tt,即缺失$.
($($program:tt),* ; $(data:tt),*)
Run Code Online (Sandbox Code Playgroud)
修复允许编译进行.
log_syntax! 在这种情况下并不是立即有用,但它仍然是一个简洁的工具:它需要任意参数并在展开时打印出来,例如
#![feature(log_syntax)]
log_syntax!("hello", 1 2 3);
fn main() {}
Run Code Online (Sandbox Code Playgroud)
将"hello" , 1 2 3在编译时打印.这对于检查其他宏调用中的内容非常有用.
(一旦你有扩展工作,调试生成的代码中的任何问题的最好的工具是使用--pretty expanded参数rustc.注意.这需要-Z unstable-options传递标志来激活它.)
Geo*_*off 15
另一个用于轻松查看扩展的好工具是cargo-expand。
它可以安装:
cargo install cargo-expand
Run Code Online (Sandbox Code Playgroud)
然后非常简单地用作:
cargo expand
Run Code Online (Sandbox Code Playgroud)
或者更精确地定位特定的测试文件(例如,tests/simple.rs):
cargo expand --test simple
Run Code Online (Sandbox Code Playgroud)
请务必查看--help,有很多选项可以缩小扩展的范围。您甚至可以针对单个项目(结构、fns 等)进行扩展!
| 归档时间: |
|
| 查看次数: |
6494 次 |
| 最近记录: |