nom中如何区分负号和负数?

How to distinguish between minus sign and negative number in nom?

使用解析器生成器 nom,我如何编写一个解析器来提取术语 1-21*-2 中减号的差异?

在第一个示例中,我期望标记 1-2。在第二个中,"minus" 符号指定数字为负数。预期的标记为 1*-2。不是 1*-2

如何使 nom 有状态,具有用户定义的状态,例如 expect_literal: bool

我目前找到的最佳解决方案是使用 nom_locate,跨度定义为

use nom_locate::LocatedSpanEx;

#[derive(Clone, PartialEq, Debug)]
struct LexState {
    pub accept_literal: bool,
}

type Span<'a> = LocatedSpanEx<&'a str, LexState>;

然后可以通过

修改状态
fn set_accept_literal(
    value: bool,
    code: IResult<Span, TokenPayload>,
) -> IResult<Span, TokenPayload> {
    match code {
        Ok(mut span) => {
            span.0.extra.accept_literal = value;
            Ok(span)
        }
        _ => code,
    }
}

其中 TokenPayload 是代表我的令牌内容的枚举。

现在你可以编写运算符解析器了:

fn mathematical_operators(code: Span) -> IResult<Span, TokenPayload> {
    set_accept_literal(
        true,
        alt((
            map(tag("*"), |_| TokenPayload::Multiply),
            map(tag("/"), |_| TokenPayload::Divide),
            map(tag("+"), |_| TokenPayload::Add),
            map(tag("-"), |_| TokenPayload::Subtract),
            map(tag("%"), |_| TokenPayload::Remainder),
        ))(code),
    )
}

整数解析器为:

fn parse_integer(code: Span) -> IResult<Span, TokenPayload> {
    let chars = "1234567890";
    // Sign ?
    let (code, sign) = opt(tag("-"))(code)?;
    let sign = sign.is_some();
    if sign && !code.extra.accept_literal {
        return Err(nom::Err::Error((code, ErrorKind::IsNot)));
    }
    let (code, slice) = take_while(move |c| chars.contains(c))(code)?;
    match slice.fragment.parse::<i32>() {
        Ok(value) => set_accept_literal(
            false,
            Ok((code, TokenPayload::Int32(if sign { -value } else { value }))),
        ),
        Err(_) => Err(nom::Err::Error((code, ErrorKind::Tag))),
    }
}

这可能无法赢得选美比赛,但它确实有效。剩下的部分应该是微不足道的。