Ambiguous variant and boost spirit x3

前端 未结 1 2046
無奈伤痛
無奈伤痛 2021-02-14 16:36

Trying to tweak the boost spirit x3 calc example to parse functions that can take functions as arguments. However it does not compile.

namespace client{ namespa         


        
1条回答
  •  南笙
    南笙 (楼主)
    2021-02-14 16:45

    I spotted this old question. X3 has evolved a bit in the mean time and I though I'd answer it now anyways.

    I suspected that the main issue might have been with (missing) (implicit) constructors on the variant members.

    Anyhow, here's a live demo with a more lightweight grammar:

    namespace grammar_def {
        using namespace x3;
    
        rule const funct("function");
    
        auto const ts        = lexeme [ '#' >> uint_ >> '#' ];
        auto const fname     = lexeme [ '@' >> raw [ alpha >> *(alnum | '_') ] ];
        auto const expr      = ts|funct;
    
        auto const funct_def = fname >> '(' >> -expr % ',' >> ')';
    
        BOOST_SPIRIT_DEFINE(funct)
    }
    

    I also added some output streaming helpers. Note how I changed the id type to std::string for simplicity (it's hard/impossible to overload operator<< for vector without invading namespace std):

    namespace client { namespace ast {
        static std::ostream& operator<<(std::ostream& os, ts const& v) {
            using namespace boost::fusion;
            return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
        }
    
        static std::ostream& operator<<(std::ostream& os, fnc const& v) {
            using namespace boost::fusion;
            return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
        }
        template
        static std::ostream& operator<<(std::ostream& os, std::vector const& v) {
            os << "("; for (auto& el : v) os << (&el==&v[0]?"":", ") << el; return os << ")";
        }
    } }
    

    Demo

    This has more (optional) plumbing to allow for richer debug information:

    Live On Coliru

    //#define BOOST_SPIRIT_X3_DEBUG
    #include 
    #include 
    #include 
    #include 
    #include 
    
    namespace client { namespace ast {
        struct ts;
        struct fnc;
    
        //using string = std::vector;
        using string = std::string; // for easier printing/debugging
    
        struct ts {
            unsigned int id;
            ts(unsigned id=0):id(id) {}
        };
    
        typedef boost::variant > node;
    
        struct fnc {
            string id;
            std::vector args;
        };
    } }
    
    BOOST_FUSION_ADAPT_STRUCT(client::ast::ts, id)
    BOOST_FUSION_ADAPT_STRUCT(client::ast::fnc, id, args)
    
    //namespace std { static ostream& operator<<(ostream&os, vector const& v) { return os.write(&v[0], v.size()); } }
    
    namespace client { namespace ast {
        static std::ostream& operator<<(std::ostream& os, ts const& v) {
            using namespace boost::fusion;
            return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
        }
    
        static std::ostream& operator<<(std::ostream& os, fnc const& v) {
            using namespace boost::fusion;
            return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
        }
        template
        static std::ostream& operator<<(std::ostream& os, std::vector const& v) {
            os << "("; for (auto& el : v) os << (&el==&v[0]?"":", ") << el; return os << ")";
        }
    } }
    
    namespace client {
        namespace x3 = boost::spirit::x3;
        namespace grammar_def {
            using namespace x3;
    
            x3::rule const funct("function");
    
            auto const ts     // = x3::rule {"timeseries"}
                                 = lexeme [ '#' >> uint_ >> '#' ];
            auto const fname  // = x3::rule {"function_name"}
                                 = lexeme [ '@' >> raw [ alpha >> *(alnum | '_') ] ];
            auto const expr   // = rule {"expr"}
                                 = ts|funct;
    
            auto const funct_def = fname >> '(' >> -expr % ',' >> ')';
    
            BOOST_SPIRIT_DEFINE(funct)
        }
    
        auto const& grammar = x3::skip(x3::space) [grammar_def::funct];
    }
    
    #include 
    
    int main() {
        std::string const s {
            "@pow( #1#, \n"
                "     @trunc(\n"
                "           @pi ()\n"
                "   ) )"};
        std::cout << "Parsing '" << s << "'\n";
    
        auto f = s.begin();
        client::ast::fnc parsed;
    
        if (parse(f, s.end(), client::grammar, parsed)) {
            std::cout << "Parse succeeded: " << parsed << "\n";
        } else {
            std::cout << "Parse failed\n";
        }
    
        if (f != s.end())
            std::cout << "Remaining unparsed input: '" << std::string(f, s.end()) << "'\n";
    }
    

    Prints:

    Parsing '@pow( #1#, 
         @trunc(
               @pi ()
       ) )'
    Parse succeeded: pow(1, trunc(pi()))
    

    0 讨论(0)
提交回复
热议问题