如何使用引号包发出具有非十进制基数的整数文字?

Posted

技术标签:

【中文标题】如何使用引号包发出具有非十进制基数的整数文字?【英文标题】:How can I emit an integer literal with a non-decimal base using the quote crate? 【发布时间】:2020-10-24 17:17:27 【问题描述】:

我正在使用quote 生成代码来解码汇编操作。我的芯片的说明手册使用二进制值来描述操作,所以我希望我生成的代码也将文字表示为二进制值,以便我更容易抽查正确性。

我找不到指定方法。 proc_macro2::Literal 提供了多种控制文字的 后缀 的方法(u8i32 等),但我没有看到任何可以控制文字基础的方法。

我的理想格式是基数 2,每四位使用一个下划线,并以适当的后缀结尾,但只需要基数。

use quote::quote; // 1.0.6

fn main() 
    let value = 0b0101_0101_u8;

    let code = format!("", quote!  #value );
    
    assert_eq!("0b0101_0101_u8", code);

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `"0b0101_0101_u8"`,
 right: `"85u8"`', src/main.rs:8:5

【问题讨论】:

【参考方案1】:

您可以使用format! 将数字格式化为字符串,然后从中构造一个TokenStream,然后您可以在quote! 中使用它:

use proc_macro2::TokenStream;
use quote::quote; // 1.0.6
use std::str::FromStr;

fn main() 
    let value = 0b0101_0101_u8;
    let value_formatted = TokenStream::from_str(&format!("0b:08b_u8", value)).unwrap();
    let code = format!(
        "",
        quote! 
            #value_formatted
        
    );

    assert_eq!("0b01010101_u8", code);

format! 宏不支持下划线,但可以轻松扩展以使用自定义格式化程序插入它们。

【讨论】:

format!("0b:04b_:04b_u8", value >> 4, value & 0x0F)u8 解决了问题。把它放在ToBinaryLiteral 后面似乎是最简单的方法。【参考方案2】:

这是我制作的包装器类型,利用实现outlined by Peter Hall 和下划线建议from E_net4:

use quote::quote; // 1.0.6

fn main() 
    let value = AsBits(0b0101_0101_u8);

    let code = format!("", quote!  #value );

    assert_eq!("0b0101_0101_u8", code);

use proc_macro2::TokenStream; // 1.0.17
use quote::ToTokens; // 1.0.6
use std::str::FromStr;

struct AsBits<T>(T);

impl ToTokens for AsBits<u8> 
    fn to_tokens(&self, tokens: &mut TokenStream) 
        let b = format!(
            "0b:04b_:04b_u8",
            (self.0 & 0xF0) >> 4,
            (self.0 & 0x0F) >> 0,
        );

        tokens.extend(TokenStream::from_str(&b).unwrap());
    

【讨论】:

以上是关于如何使用引号包发出具有非十进制基数的整数文字?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用复合文字来“fprintf()”具有任意基数的多个格式化数字?

非负整数的基数排序(按位)

verilog入门-----表达式

您如何在 ruby​​ 中编写二进制文字?

如何在 Python 中解析十六进制或十进制整数 [重复]

以其他基数表示负数