Boost Spirit罗马数字解析器示例

Boost Spirit Roman Numeral Parser Example

本文关键字:Spirit 罗马 数字 Boost      更新时间:2023-10-16

尝试学习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') ?因为毕竟不能有0个或多个M而不是1个或多个M吗?

Spirit中的a || b运算符是指ab,如果出现a,则a之后是b。在运算符的含义中,没有M的情况是隐含的(因为M的匹配可能存在,也可能不存在)。此外,在*lit('M')的情况下,如果有NO M,您会说第一个规则是匹配的吗?无论如何,它都是有效的,并且_val将增加1000。

+lit('M')*lit('M')都正确。但在我看来,前者比后者更具可读性(语义上),因为前者说如果有one匹配,则将 1000添加到_val,并重复执行。另一方面,后者很难读取,因为人们可以将其读取为 1000添加到_val,即使是零匹配也是错误的。1000没有被添加到_val进行零次匹配,然而解析器*lit('M')似乎也匹配零次匹配(似乎有点令人困惑)。

所以+lit('M')是最好的。


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

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

在Qi中匹配表达式A || B意味着只匹配A,或者只匹配BA followed by B。因此,在您的示例中,+lit('M') || hundreds表示+lit('M')hundreds+lit('M')followed by hundreds。由于这个原因,语法允许匹配任何罗马数字,甚至不以M开头。