Boost Spirit罗马数字解析器示例

5

我正在尝试学习boost spirit,但文档中给出的示例让我有些困惑。

参考这段代码:

http://www.boost.org/doc/libs/1_46_1/libs/spirit/example/qi/roman.cpp

特别是语法的这一部分:

        start = eps             [_val = 0] >>
            (
                +lit('M')       [_val += 1000]
                ||  hundreds    [_val += _1]
                ||  tens        [_val += _1]
                ||  ones        [_val += _1]
            )

有人能解释一下为什么是+lit('M')而不是*lit('M')吗?毕竟可能是零个或多个M,而不是一个或多个M。

4个回答

2
在Spirit中,a || b 运算符表示 a 或者 b,但如果出现了 a,那么后面的 b 将被忽略。在运算符的意义上,没有 M 的情况是隐含的(因为匹配 M 可能存在或不存在)。此外,在 *lit('M') 的情况下,如果没有 M,你会认为第一个规则已经匹配了吗?无论如何它都是有效的,并且 _val 将增加 1000。

但是当没有M时,_val不会增加。我尝试使用输入CCLIX,无论我使用+还是*,它都返回正确的值259。 - Integer
这可能取决于具体实现。从语义上讲,规则“可以”匹配(因此可以执行代码),因此最好使用“+”,因为0匹配已经被“||”运算符隐含了。 - Diego Sevilla

0

+lit('M')*lit('M') 都是正确的。但在我的看法中,前者比后者(语义上)更易读,因为前者表示如果有一个匹配,则添加 1000_val 中,并重复执行。另一方面,后者很难阅读,因为人们可能会将其解读为即使是零匹配也要添加 1000_val 中,这是错误的。对于零次匹配,1000 不会添加到 _val 中,但解析器 *lit('M') 似乎也可以用于零匹配(似乎有点令人困惑)。

因此,+lit('M') 更可取。


好的,我看到了你的评论。 CCLLIX 不是一个有效的罗马数字。你认为它的值是多少?309?如果是这样,那么 CCCIX 的值会是什么呢?它也是 309,而且是正确的。你的是错误的。因此,当你使用 *lit('M') 时,解析器会停止。请注意,即使对于这个错误的输入,如果你使用 +lit('M'),解析器也会停止。


使用 *lit('M') 和 CCLLIX,为什么结果返回250并停在LIX?就像你说的那样,如果没有匹配项,并且 CCLLIX 没有 M,它不应该为 _val 添加1000吗?所以它不应该返回1250而不是250吗? - Integer
1
@整数:我已经添加了解释。 CCLLIX 不是一个有效的数字。 - Nawaz
好的发现。对此我很抱歉。但是,即使我使用CCLIX,在使用和+时都会得出正确答案259。为什么像你所说的那样,不会得出1259的结果? - Integer
@整数:我意识到对于零匹配,_val 没有被更新。因此,我纠正了我的答案。 - Nawaz

0

它是(一个或多个M)或数百或数十或个位数。零个或多个M,数百,数十或个位数将不匹配任何M,即空字符串,并且毫无意义地添加1000。


这不是真的。我尝试传递一个空字符串,使用Kleene星号解决方案*lit('M')时它没有添加1000。 - Integer

0
在 Qi 中,匹配表达式 A || B 意味着匹配仅 A,或仅 B,或者 A 后跟 B。因此,在您的情况下,+lit('M') || hundreds 表示 +lit('M'),或者 hundreds,或者 +lit('M') 后跟 hundreds。因此,语法允许匹配任何罗马数字,甚至不以 M 开头。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接