Using spirit to parse into classes?

馋奶兔 提交于 2019-12-11 04:03:58

问题


Below is the employee.cpp source file from the boost spirit documentation. It's 'struct employee' followed by a macro that tells fusion about 'struct employee', followed by the employee parser.

I am trying to adapt this for my purposes, but rather than use 'struct employee', I have a number of classes that I'd like to use in place of 'struct employee'.

I was looking at trying to replace 'struct employee' for classes, but I don't see the macros to do that in fusion? And the reason I don't want to put it in the struct is because I'd then have to copy it over from struct to my class, and that just seems unnecessary, not to mention the performance hit.

After thinking about it a bit more, I may not be understanding the purpose for Fusion and tuples, and therefore, maybe I have to use it that way and then move data into my own class structures.

Any guidance?

namespace client { namespace ast
{
    ///////////////////////////////////////////////////////////////////////////
    //  Our employee struct
    ///////////////////////////////////////////////////////////////////////////
    struct employee
    {
        int age;
        std::string surname;
        std::string forename;
        double salary;
    };

    using boost::fusion::operator<<;
}}

// We need to tell fusion about our employee struct
// to make it a first-class fusion citizen. This has to
// be in global scope.

BOOST_FUSION_ADAPT_STRUCT(
    client::ast::employee,
    (int, age)
    (std::string, surname)
    (std::string, forename)
    (double, salary)
)

namespace client
{
    ///////////////////////////////////////////////////////////////////////////////
    //  Our employee parser
    ///////////////////////////////////////////////////////////////////////////////
    namespace parser
    {
        namespace x3 = boost::spirit::x3;
        namespace ascii = boost::spirit::x3::ascii;

        using x3::int_;
        using x3::lit;
        using x3::double_;
        using x3::lexeme;
        using ascii::char_;

        x3::rule<class employee, ast::employee> const employee = "employee";

        auto const quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];

        auto const employee_def =
            lit("employee")
            >> '{'
            >>  int_ >> ','
            >>  quoted_string >> ','
            >>  quoted_string >> ','
            >>  double_
            >>  '}'
            ;

        BOOST_SPIRIT_DEFINE(employee);
    }
} 

回答1:


There is no difference between struct and class¹.

With that out of the way, what people usually mean is "I want classes without direct data member ("field") access".

Now I could point you straight at BOOST_FUSION_ADAPT_ADT. That's what you are looking for.

However.

This implies that you have exposed setters for all your data members anyways. That's a giant anti-pattern², as it just leads to Quasi-Classes³.

Consider using factory functions (adapt them using Phoenix to call from semantic actions // but see Boost Spirit: "Semantic actions are evil"?) or, indeed having a clean AST representation which you then use to build the domain object graph from.

If you can't afford doing that (because of the copies) you can't really afford Spirit V2 IMO. Spirit is geared towards rapid development/prototyping of (changing) grammars while not generating atrocious code. But if you can't afford copies it's time to hand-roll your parser (or move to Spirit X3)


¹ literally the only difference is struct makes all members public by default, but you can still use private: and protected:

² likely originating in the history of Java's PoJo or "Bean"

³ "Pseudo-Classes and Quasi-Classes Confuse Object-Oriented Programming"



来源:https://stackoverflow.com/questions/44581141/using-spirit-to-parse-into-classes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!