使用解析器生成器nom1-2
,我如何编写一个解析器来提取术语和中减号的差异1*-2
?
在第一个示例中,我期望标记1
和。在第二个中,“减号”表示负数。预期的标记是和。不是,和。_-
2
1
*
-2
1
*
-
2
如何使用用户定义的状态使 nom 有状态,例如expect_literal: bool
?
使用解析器生成器nom1-2
,我如何编写一个解析器来提取术语和中减号的差异1*-2
?
在第一个示例中,我期望标记1
和。在第二个中,“减号”表示负数。预期的标记是和。不是,和。_-
2
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))),
}
}
这可能不会赢得选美比赛,但它确实有效。剩下的部分应该是微不足道的。