nom中如何区分负号和负数?
How to distinguish between minus sign and negative number in nom?
使用解析器生成器 nom,我如何编写一个解析器来提取术语 1-2
和 1*-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))),
}
}
这可能无法赢得选美比赛,但它确实有效。剩下的部分应该是微不足道的。
使用解析器生成器 nom,我如何编写一个解析器来提取术语 1-2
和 1*-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))),
}
}
这可能无法赢得选美比赛,但它确实有效。剩下的部分应该是微不足道的。