-4

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

在第一个示例中,我期望标记1和。在第二个中,“减号”表示负数。预期的标记是和。不是,和。_-21*-21*-2

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

4

1 回答 1

1

我现在找到的最佳解决方案是使用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))),
    }
}

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

于 2019-08-20T16:18:38.003 回答