Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8882931
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 14, 20262026-06-14T20:41:46+00:00 2026-06-14T20:41:46+00:00

I am trying to add a greater than operator > to a ast: the

  • 0

I am trying to add a greater than operator > to a ast: the code is 95% identical to the code in the docs.

Two points of interest below

  • A block of code where I’m trying to write support for greater than: commented in the code below.
  • A single line in the parse for term which fails to compile because I don’t yet understand semantic actions yet: not sure how to bind the lhs of lhs > rhs through phoenix and semantic actions.

The solution should be trivial for regular users of Spirit, but I am still learning, and only getting by through examples so far.

Any help would be appreciated. TIA.

Code

#define BOOST_SPIRIT_DEBUG

#include <boost/spirit/include/qi.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/classic_symbols.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>   // std::regex not fully implemented in stdc++ yet

#include <string>
#include <map>
#include <utility>
#include <functional>
#include <iostream>
#include <string>
#include <vector>

namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    struct binary_op;
    struct unary_op;
    struct nil {};

    struct expression_ast
    {
        typedef
        boost::variant<
        nil // can't happen!
        , double
        , std::string
        , boost::recursive_wrapper<expression_ast>
        , boost::recursive_wrapper<binary_op>
        , boost::recursive_wrapper<unary_op>
        >
        type;

        expression_ast()
            : m_expr(nil()) {}

        template <typename Expr>
        expression_ast(Expr const& expr)
            : m_expr(expr) {}

        expression_ast& operator+=(expression_ast const& rhs);
        expression_ast& operator-=(expression_ast const& rhs);
        expression_ast& operator*=(expression_ast const& rhs);
        expression_ast& operator/=(expression_ast const& rhs);


        type m_expr;
    };

    struct binary_op
    {
        binary_op(
            char op
            , expression_ast const& left
            , expression_ast const& right)
            : m_op(op), m_left(left), m_right(right) {}

        char m_op;
        expression_ast m_left;
        expression_ast m_right;
    };

    struct unary_op
    {
        unary_op(
            char op
            , expression_ast const& subject)
            : m_op(op), m_subject(subject) {}

        char m_op;
        expression_ast m_subject;
    };

    expression_ast& expression_ast::operator+=(expression_ast const& rhs)
    {
        m_expr = binary_op('+', m_expr, rhs);
        return *this;
    }

    expression_ast& expression_ast::operator-=(expression_ast const& rhs)
    {
        m_expr = binary_op('-', m_expr, rhs);
        return *this;
    }

    expression_ast& expression_ast::operator*=(expression_ast const& rhs)
    {
        m_expr = binary_op('*', m_expr, rhs);
        return *this;
    }

    expression_ast& expression_ast::operator/=(expression_ast const& rhs)
    {
        m_expr = binary_op('/', m_expr, rhs);
        return *this;
    }

    // We should be using expression_ast::operator-. There's a bug
    // in phoenix type deduction mechanism that prevents us from
    // doing so. Phoenix will be switching to BOOST_TYPEOF. In the
    // meantime, we will use a phoenix::function below:
    struct negate_expr
    {
        template <typename T>
        struct result
        {
            typedef T type;
        };

        expression_ast operator()(expression_ast const& expr) const
        {
            return expression_ast(unary_op('-', expr));
        }
    };

    static boost::phoenix::function<negate_expr> neg;

    struct ast_print
    {
        typedef std::string result_type;

        std::string operator()(qi::info::nil) const
        {
            return "";
        }
        std::string operator()(std::string const& str) const
        {
            return str;
        }
        std::string operator()(double d) const
        {
            std::ostringstream oss;
            oss << d;
            return oss.str();
        }

        std::string operator()(expression_ast const& ast) const
        {
            return boost::apply_visitor(*this, ast.m_expr);
        }

        std::string operator()(binary_op const& expr) const
        {
            std::ostringstream oss;
            oss << "op:" << expr.m_op << "(";
            oss << boost::apply_visitor(*this, expr.m_left.m_expr);
            oss << ", ";
            oss << boost::apply_visitor(*this, expr.m_right.m_expr);
            oss << ')';
            return oss.str();
        }

        std::string operator()(unary_op const& expr) const
        {
            std::ostringstream oss;
            oss << "op:" << expr.m_op << "(";
            oss << boost::apply_visitor(*this, expr.m_subject.m_expr);
            oss << ')';
            return oss.str();
        }
    };

    std::ostream& operator << (std::ostream& stream, const expression_ast& expr)
    {
        ast_print printer;
        stream << printer(expr) << std::endl;
        return stream;
    }

    // CODE ADDED HERE ------------------------------------------------------------
    template< char OP >
    struct binary_expr
    {
        template <typename T>
        struct result
        {
            typedef T type;
        };

        expression_ast operator()(expression_ast const& lhs,expression_ast const& rhs) const
        {
            return expression_ast(binary_op( OP, lhs, rhs ));
        }
    };

    static boost::phoenix::function<binary_expr<'>'>> gt;
    // CODE ADDED END HERE -------------------------------------------------------

    template <typename Iterator>
    struct ParserGenerator : qi::grammar<Iterator, expression_ast(), ascii::space_type>
    {
        ParserGenerator() : ParserGenerator::base_type(expression)
    {
        using qi::_val;
        using qi::_1;
        using qi::double_;
        using qi::iso8859_1::char_;
        using qi::iso8859_1::space;
        using qi::eol;
        using boost::spirit::ascii::string;

        comment =
            space >> ("//" >> *(char_ - eol) >> eol)
            ;

        expression =
            term                            [_val = _1]
            >> *(   ('+' >> term            [_val += _1])
                |   ('-' >> term            [_val -= _1])
                )
            ;

        term =
            factor                          [_val = _1]
            >> *(   ('*' >> factor          [_val *= _1])
                |   ('/' >> factor          [_val /= _1])
//          |   ('>' >> factor          [_val = gt(qi::_val,_1)]) // PROBLEM HERE!
                )
            ;

        factor =
            symbol                          [_val = _1]
            | double_                       [_val = _1]
            |   '(' >> expression           [_val = _1] >> ')'
            |   ('-' >> factor              [_val = neg(_1)])
            |   ('+' >> factor              [_val = _1])
            ;

        symbol %= 
            (symbol_raw 
            >> *( string("[") >> +qi::digit >> string("]"))
            >> *( string(".") >> symbol ))
            ;

        symbol_raw %= 
            +(qi::alpha | qi::char_( "_" ))
            ;

        BOOST_SPIRIT_DEBUG_NODE(expression);
        BOOST_SPIRIT_DEBUG_NODE(term);
        BOOST_SPIRIT_DEBUG_NODE(factor);
        BOOST_SPIRIT_DEBUG_NODE(comment);
        BOOST_SPIRIT_DEBUG_NODE(symbol);
        BOOST_SPIRIT_DEBUG_NODE(symbol_raw);
    }

    qi::rule<Iterator, expression_ast(), ascii::space_type>
        expression, term, factor, comment;

    qi::rule<Iterator, std::string(), ascii::space_type>
        symbol, symbol_raw;
    };
}

int main(int argc, char* argv[])
{
    using boost::spirit::ascii::space;
    using client::expression_ast;
    using client::ast_print;

    typedef std::string::const_iterator iterator_type;
    typedef client::ParserGenerator<iterator_type> ParserGenerator;

    ParserGenerator pg;   // our grammar
    std::string predicate( "i_.c>x[0]" );
    expression_ast  ast;
    ast_print       printer;

    iterator_type iter = predicate.begin(), end = predicate.end();
    if ( phrase_parse( iter, end, pg, space, ast ))
    {
        std::cerr << printer( ast ) << std::endl;
    }

    return 0;
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-14T20:41:47+00:00Added an answer on June 14, 2026 at 8:41 pm

    TL;DR use

    template <typename, typename> struct result { typedef expression_ast type; };
    

    inside binary_expr struct. Here’s why:


    You declare a functor object, to be used as a Phoenix lazy actor.

    The functor is what’s known as a Deferred/Polymorphic Calleable Object (PCE) in the Boost documentation. This means that the expression templates building the Phoenix actors will actually only do actual overload resolution/type deduction for the function arguments at the actual time of application.

    The function return type cannot be deduced (just like it cannot in regular (non-lazy) C++). This is where boost libraries employ the BOOST_RESULT_OF protocol.

    Note The RESULT_OF protocol is obsolete/redundant when using C++11, since C++11 has decltype. To enable that, on most compilers you need to

    #define BOOST_RESULT_OF_USE_DECLTPYE
    

    (allthough the release notes of v1_52_0 make it clear that decltype is becoming the default for compilers that support it well enough).

    What this protocol entails, is this:

    • When you use Polymorphic Calleable Object with n parameters, boost will look for a nested type typedef inside a nested class template result, parameterized with the n actual argument types. This will be the return type
    • The actual functor invocation calls operator() with those arguments. Here, C++ will be left to do the overload resolution.

    In general, you are expected to write your functor in fully parameterized style:

    template<char OP>
    struct binary_expr
    {
        template <typename, typename> struct result { typedef expression_ast type; };
    
        template <typename A, typename B>
        typename result<A,B>::type operator()(A const&a,B const&b) const {
            return expression_ast(binary_op( OP, a, b ));
        }
    };
    

    This works. However, because the actual overload resolution on argument types is done by the compiler, you can change the operator() signature to use fixed types:

    template <typename A, typename B>
    expression_ast operator()(A const&a,B const&b) const {
        return binary_op(OP, a, b);
    }
    

    If you wish, you can do away with (some) template parameters:

    template <typename E>
    expression_ast operator()(E const&a,E const&b) const {
        return binary_op(OP, a, b);
    }
    

    Or even not a function template at all:

    expression_ast operator()(expression_ast const&,expression_ast const&) const;
    

    Everything is fine, as long as one overload matches the actual argument types passed. The important bit, though, is that the result<...>::type is getting evaluated regardless of the signature of operator(), and as such it will need precisely the number of arguments expected.

    Note also that you can, in this fashion, combine functors of different arity:

    template <char OP> struct operator_expr 
    {
        template <typename T, typename=T> struct result 
            { typedef expression_ast type; };
    
        expression_ast operator()(expression_ast const& expr) const
        { return expression_ast(unary_op(OP, expr)); }
    
        expression_ast operator()(expression_ast const&a, expression_ast const&b) const 
        { return binary_op(OP, a, b); }
    };
    
    static boost::phoenix::function<operator_expr<'-'>> neg;
    static boost::phoenix::function<operator_expr<'>'>> gt;
    

    This works, because both result<T>::type and result<T,U>::type are valid type expressions with this definition.


    Bonus notes:

    1. You had a strangeness there where you said

      template <typename T> struct result { typedef T type; };
      

      instead of

      template <typename> struct result { typedef expression_ast type; };
      

      This is because the return type shouls, in fact, not vary depending on the actual argument type. In your sample, the argument type would normally be the same, but it didn’t make sense technically.

    2. You can do things without the BOOST_RESULT_OF protocol if you use decltype. This means you can just drop the nested result struct

    3. You can also adapt normal functions as Phoenix actors:

      #define BOOST_SPIRIT_USE_PHOENIX_V3
      
      // ...
      
      expression_ast neg_expr(expression_ast const&a)                         { return unary_op ('-', a); }
      expression_ast gt_expr (expression_ast const&a, expression_ast const&b) { return binary_op('>', a, b); }
      
      BOOST_PHOENIX_ADAPT_FUNCTION(expression_ast, neg, neg_expr, 1)
      BOOST_PHOENIX_ADAPT_FUNCTION(expression_ast, gt,  gt_expr,  2)
      

      This will basically write the functor objects for you, including the RESULT_OF protocol bits.

    4. Finally, you can use standard Phoenix actors instead of defining custom ones. In that case, there is no need for any of the above:

      using phx = boost::phoenix;
      // ...
         |   ('>' >> factor [_val = phx::construct<binary_op>('>', _val, _1)]) // PROBLEM HERE!
      // ...
         |   ('-' >> factor [_val = phx::construct<unary_op>('-', _1)])
      

    Wrap-up

    The complete code is here: http://ideone.com/Xv9IH1 and was tested on

    • MSVC 2012, boost 1_52_0, Win64
    • GCC 4.8, boost 1_52_0, Win64
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I am trying add picture boxes dynamically. My code is as PictureBox picture =
I'm trying to work out what's going on with this code. I have two
I'm trying to get rough greater than and less than values to compare latitude
I have the following code which I am trying to add a or operation
I'm trying add data triggers to the default combobox style so each text item
Im new to asp.net mvc. I'm trying add new model class but it got
Trying to add init parameter names to a list in init(ServletConfig) method. public void
Trying to add a blank sample app for a rails tutorial to GitHub, but
Trying to add a 'box' to a form at design time, I looked up
Trying to add email notification to my app in the cleanest way possible. When

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.