布尔表达式的Spirit解析器

时间:2012-08-09 15:30:20

标签: c++ boost

我第一次使用精神。我正在尝试编写一个布尔表达式(只有&,|和!运算符)解析器。我已经定义了我的语法如下:

template <typename Iterator>
struct boolean_expression_parser : qi::grammar<Iterator, std::string(), ascii::space_type>
{
    boolean_expression_parser() : boolean_expression_parser::base_type(expr)
    {
        using namespace qi;
        using ascii::char_;
        using boost::spirit::ascii::alnum;
        using namespace qi::labels;

        using phoenix::construct;
        using phoenix::val;

        operand %= lexeme[+(alnum)];

        simple_expr %= ('(' > expr > ')') | operand;

        unary_expr  %= ('!' > simple_expr ) ;

        and_expr %= ( expr > '*' > expr);

        or_expr  %= (expr > '|' > expr);

        expr %= simple_expr | unary_expr | *and_expr | *or_expr;

        // on_error<fail>
        //         (
        //             unary_expr,
        //             std::cout
        //             << val("Error! Expecting ")
        //             << _4                               // what failed?
        //             << val(" here: \"")
        //             << construct<std::string>(_3, _2)   // iterators to error-pos, end
        //             << val("\"")
        //             << std::endl
        //          );
    }

    qi::rule<Iterator, std::string(), ascii::space_type> operand;
    qi::rule<Iterator, std::string(), ascii::space_type> simple_expr;
    qi::rule<Iterator, std::string(), ascii::space_type> unary_expr;
    qi::rule<Iterator, std::string(), ascii::space_type> and_expr;
    qi::rule<Iterator, std::string(), ascii::space_type> or_expr;
    qi::rule<Iterator, std::string(), ascii::space_type> expr;
};

我在这里面临一些障碍:

  1. 它不适用于任何二进制表达式(如'A + B')。它适用于一元表达式(如'!(A)'或'(!A)'。
  2. 有人能指出我做错了吗?

    1. 我想以树形式存储它(因为我想用它构建一个BDD)。有人能指出我该怎么做吗?

    2. 另外,为什么on_error&lt;&gt;即使我启用它也无法正常工作?

    3. 我正在使用boost 1.49和gcc-4.2.2。

      此致 〜Soumen

1 个答案:

答案 0 :(得分:3)

您的解析器存在很多问题。首先,您在这里遇到左侧递归,因此解析器将因 Stack Overflow 而崩溃。你的语法应该是这样的:

expr = or_expr;
or_expr = and_expr >> -('|' > expr);
and_expr = unary_expr >> -('*' > expr);
unary_expr = ('!' > expr) | operand | ('(' >> expr > ')');

在这种情况下,你没有左递归和一切都解析。

为什么你的方法失败了?在你的情况下:

input: A * B
1: expr
  1.1: check simple_expr 
       -> fail at '(', try next
       -> operand matches, return from simple_expr
  matched, return.

所以它应该只解析A,并且必须返回,但输入未完全解析。

此外,您过度使用了运营商>。它的目的是在它之后没有匹配时解析失败。另一方面,运算符>>返回并让解析器检查其他可能性。