2

I am trying to write a parser for boolean expressions using boost spirit. I found a great example here on stackoverflow.com, Boolean expression (grammar) parser in c++, that helped me a lot understanding how the spirit grammars and the parsing process work.

The code compiles and runs perfectly on my dev machine which is a debian 6 box with 2.6.32-5 bigmem kernel and boost 1.42 (spirit 2.2) installed. I decided to modify the code for my purposes in order to parse not only expressions in the form of: "a and b or c" but also expressions of the form "sc[100] and cc[200] or fd[300]", where the operands of the boolean operation also need to be parsed in order to get an ast as i need it for my project. I chose the following approach:

  • add another abstract data type

    struct op_or  {};
    struct op_and {};
    struct op_xor {};
    struct op_not {};
    struct r_sc  {};
    
    typedef std::string var;
    template <typename tag> struct binop;
    template <typename tag> struct unop;
    template <typename tag> struct rule;
    
    typedef boost::variant<
            var,
            boost::recursive_wrapper<unop<op_not>>,
            boost::recursive_wrapper<binop<op_and>>,
            boost::recursive_wrapper<binop<op_xor>>,
            boost::recursive_wrapper<binop<op_or>>,
            boost::recursive_wrapper<rule<r_sc>> > expr;
    
    template <typename tag> struct rule
    {
        explicit rule( const expr& lhs, const expr& rhs )
            :   oper1( lhs ),
                oper2( rhs )
        {
    
        }
    
        expr oper1, oper2;
    };
    
    
    
    template <typename tag> struct binop
    {
        explicit binop( const expr& lhs, const expr& rhs )
            :   oper1( lhs ),
                oper2( rhs )
        {
    
        }
    
        expr oper1, oper2;
    };
    
    
    
    template <typename tag> struct unop
    {
        explicit unop( const expr& rhs )
            :   oper1( rhs )
        {
    
        }
    
        expr oper1;
    };
    
  • modify the visitor for printing the ast

    struct printer : boost::static_visitor<void>
    {
        printer( std::ostream& outputStream )
            :   _outputStream( outputStream )
        {
    
        }
    
        std::ostream& _outputStream;
    
        //
        void operator()( const var& variable ) const
        {
            _outputStream << variable;
        }
    
        void operator()( const binop<op_and>& binaryOp ) const
        {
             printOp( " & ", binaryOp.oper1, binaryOp.oper2 );
        }
    
        void operator()( const binop<op_or>& binaryOp ) const
        { 
            printOp( " | ", binaryOp.oper1, binaryOp.oper2 );
        }
    
        void operator()( const binop<op_xor>& binaryOp ) const
        {
            printOp( " ^ ", binaryOp.oper1, binaryOp.oper2 );
        }
    
    void printOp( const std::string& operation, const expr& lhs, const expr& rhs ) const
    {
        _outputStream << "(";
            boost::apply_visitor( *this, lhs );
            _outputStream << operation;
            boost::apply_visitor( *this, rhs );
        _outputStream << ")";
    }
    
    void operator()( const unop<op_not>& uaryOp ) const
    {
        _outputStream << "(";
        _outputStream << "!";
            boost::apply_visitor( *this, uaryOp.oper1 );
        _outputStream << ")";
    }
    
    void operator()( const rule<r_sc>& rule ) const
    {
        printRule( " serviceCode ", rule.oper1, rule.oper2 );
    }
    
    void printRule( const std::string& rule, const expr& lhs, const expr& rhs ) const
    {
        _outputStream << "{";
            boost::apply_visitor( *this, lhs );
            _outputStream << rule;
            boost::apply_visitor( *this, rhs );
        _outputStream << "}";
    }
    };
    
  • modify the grammar rules for generating also rule objects

    template <typename It, typename Skipper = qi::space_type>
    struct parser : qi::grammar<It, expr(), Skipper>
    {
        parser()
            : parser::base_type( _expr )
        {
            using namespace qi;
            using boost::spirit::ascii::string;
    
            _expr  = _or.alias();
    
            _or = ( _xor >> "or" >> _or )[ _val = phx::construct<binop<op_or> >( _1, _2 ) ] |
                _xor   [ _val = _1 ];
    
            _xor = ( _and >> "xor" >> _xor )[ _val = phx::construct<binop<op_xor> >( _1, _2 ) ] |
                _and[ _val = _1 ];
    
            _and = ( _not >> "and" >> _and )[ _val = phx::construct<binop<op_and> >( _1, _2 ) ] |
                _not[ _val = _1 ];
    
            _not = ( "not" > _base )[ _val = phx::construct<unop<op_not> >( _1 ) ] |
                _base[ _val = _1 ];
    
            _base = ( ( '(' > _expr > ')' ) | _serviceCode[ _val = _1 ] );
    
            _serviceCode = ( +alnum >> "[" >> +alnum >> "]" )
                [ _val = phx::construct<rule<r_sc> >( _1, _2 ) ] |
                    _text;
    
            _text = qi::lexeme[ +( alnum ) ];
        }
    private:
    
            qi::rule<It, var() , Skipper> _text;
            qi::rule<It, expr(), Skipper> _not, _and, _xor, _or, _base, _expr, _serviceCode;
    };
    

I thought this is it, but this solution does not even compile. the compiler pukes the following error:

error: parse error in template argument list error: no match for ‘operator>’ in ‘construct<<expression error> > > (boost::spirit::_1, boost::spirit::_2)’

As I am very new to boost spirit, can somebody please give me a hint what I am doing wrong?

Community
  • 1
  • 1
  • just saw the complete typedef for expr got lost: – user1661910 Sep 11 '12 at 06:43
  • typedef boost::variant< var, boost::recursive_wrapper >, boost::recursive_wrapper >, boost::recursive_wrapper >, boost::recursive_wrapper >, boost::recursive_wrapper > > expr; – user1661910 Sep 11 '12 at 06:43
  • sorry but i cannot not figure out the difference betweene: _val = phx::construct >( _1, _2 ) and: _val = phx::construct >( _1, _2 )? for me they look identical. – user1661910 Sep 11 '12 at 08:37
  • Not sure if that has anything to do with your problem, but you are using `rule` as parameter name in several places. Try using another name. – Henrik Sep 11 '12 at 09:10
  • 1
    As @Henrik notes, the problem lies in a collision between `qi::rule` (with the `using namespace qi` directive) and your own `rule`. –  Sep 11 '12 at 09:15
  • oh man thx for this hint. staring at template compiler errors made me loose the focus for the problem. renaming the template solved the problem. – user1661910 Sep 11 '12 at 09:19
  • @llonesmiz I had only a vague idea that some sort of name clash might be the problem. You found the exact cause. Make it an answer and I'll upvote it. – Henrik Sep 11 '12 at 09:24

0 Answers0