21

だから私はデバッグしようとしている次のマクロコードを持っています。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);

マクロのどこから問題が発生しているのかを突き止めるには、どのような手順を実行すればよいですか?

これが私のコードです:

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);
}            
4

3 に答える 3

38

展開に失敗したマクロをデバッグするには、主に次の 2 つの方法があります。

  • trace_macros!
  • log_syntax!

(NB. どちらも同じ名前の機能の下で機能ゲートされているため、ナイトリー コンパイラが動作する必要があり、multirustこの種の作業のためにバージョンを簡単に切り替えることができます。)

trace_macros!(...)マクロ トレースのオンまたはオフを切り替えるブール値の引数を取ります (つまり、ステートフルです)。オンの場合、コンパイラは各マクロ呼び出しを、展開された引数と共に出力します。通常、コードの先頭に次のコードを追加trace_macros!(true);する場合など、クレートの先頭に呼び出しをスローしたいだけです。

#![feature(trace_macros)]

trace_macros!(true);

出力は次のようになります。

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

うまくいけば問題が絞り込まれます:bct_p!呼び出しは何らかの形で無効です。注意深く見ると、問題が明らかになります。2 番目のアームの左側が、bct_p使用data:ttすべきときに を使用しています。$data:ttつまり、欠落してい$ます。

    ($($program:tt),* ; $(data:tt),*)

コンパイルが進行できるように修正。

log_syntax!この場合、すぐに役立つわけではありませんが、それでもきちんとしたツールです。任意の引数を取り、展開するとそれらを出力します。

#![feature(log_syntax)]

log_syntax!("hello", 1 2 3);

fn main() {}

"hello" , 1 2 3コンパイルすると出力されます。これは、他のマクロ呼び出し内のものを検査するのに最も役立ちます。

(展開が機能するようになったら、生成されたコードの問題をデバッグするための最良のツールは、.NB への--pretty expanded引数を使用することrustcです。これ-Z unstable-optionsを有効にするには、フラグを渡す必要があります。)

于 2015-05-13T07:24:11.617 に答える