有条件地使用nom解析基于先前元素的数组

时间:2018-04-06 16:03:16

标签: parsing rust nom

我需要从一个u8数组中解析一个32位整数(小端)的数组,但是如果设置了当前int的第31位,则只存在下一个int。如果其余部分不存在则应将数组的其余部分设置为零。我不确定如何有条件地解析下一个元素。

让我们说该字段长4个字节。那么parse_field函数的结果就是用le_u32解析4个字节,这将是[u32; 8]数组。但是,如果设置了该字段的第31位。然后存在另外4个字节,也像这个字段,它进入数组的下一个元素。如果未设置则函数必须返回,其余元素的数组设置为零。现在每个现有领域都在继续。

例如,对于以下输入:

0x8000000a
0x8000000b
...

你会得到[0x8000000a, 0x8000000b, 0, 0, 0, 0, 0, 0]

但是如果输入是

0x8000000a
0x8000000b
0x8000000c
0x8000000d
0x8000000e
....

然后你会得到[0x8000000a, 0x8000000b, 0x8000000c, 0x8000000d, 0x8000000e, 0, 0, 0]

extern crate nom;

use nom::*;

#[derive(Clone, Copy, Debug)]
struct Derp {
    field: [u32; 8]
}

named!(parse_field<[u32; 8]>,

    // what do I do here

);


named!(parse_derp<Derp>,
    do_parse!(
        field: parse_field >>
        (Derp {
            field: field
        })
    )
);

fn main() {
    let temp = [0x0a, 0x00, 0x00, 0x80, 0x0b, 0x00, 0x00, 0x80];
    println!("{:?}", parse_derp(&temp));
}

在这里使用Vec也可能更好吗?

1 个答案:

答案 0 :(得分:1)

这是一个与输入的最后u32匹配的解析器:

named!(last_u32<u32>,
  verify!(le_u32, |n:u32| (n & 0b1) != 0) // Matches iff the 31st bit is set
);

然后您可以像这样使用它:

named!(parse_field<Vec<u32>>,
  map!(
    many_till!(le_u32, last_u32),
    |(mut v,n)| { v.push(n); v } // Add the last u32 to the vector
  ) 
);