logo
down
shadow

Boost Spirit X3: Collapsing one-element lists


Boost Spirit X3: Collapsing one-element lists

By : user2183669
Date : November 16 2020, 04:01 AM
Hope that helps Say I have a (simplified) recursive grammar like this:
code :
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>

namespace x3 = boost::spirit::x3;

namespace burningmime::setmatch::ast
{
    // an expression node (either an AND or an OR)
    struct Expr;

    // child of an expression -- either another expression, or a terminal
    struct Node : x3::variant<std::string, x3::forward_ast<Expr>>
    {
        using base_type::base_type;
        using base_type::operator=;
    };

    // tags for expression type
    enum OPER
    {
        OPER_AND = 1,
        OPER_OR = 2
    };

    // see above
    struct Expr
    {
        OPER op;
        std::vector<Node> children;
    };

    // for debugging purposes; this will print all the expressions
    struct AstPrinter
    {
        void operator()(const Expr& node) const
        {
            std::cout << (node.op == OPER_AND ? "And(" : "Or(");
            bool first = true;
            for(const auto& child : node.children)
            {
                if(!first) std::cout << ", ";
                first = false;
                boost::apply_visitor(*this, child);
            }
            std::cout << ")";
        }

        void operator()(const std::string& node) const
        {
            std::cout << node;
        }
    };
}

 // these need to be at top-level scope
 // basically this adds compile-time type information, so the parser knows where to put various attributes
BOOST_FUSION_ADAPT_STRUCT(burningmime::setmatch::ast::Expr, op, children)

#define DECLARE_RULE(NAME, TYPE) static const x3::rule<class NAME##_r, TYPE> NAME = #NAME;
#define KEYWORD(X) static const auto kw_##X = x3::no_case[#X];
#define DEFINE_RULE(NAME, GRAMMAR) \
    static const auto NAME##_def = GRAMMAR; \
    BOOST_SPIRIT_DEFINE(NAME)

namespace burningmime::setmatch::parser
{
    // we need to pre-declare the rules so they can be used recursively
    DECLARE_RULE(Phrase,    std::string)
    DECLARE_RULE(Term,      ast::Node)
    DECLARE_RULE(AndExpr,   ast::Node)
    DECLARE_RULE(OrExpr,    ast::Node)
    DECLARE_RULE(ParenExpr, ast::Node)

    // keywords
    KEYWORD(and)
    KEYWORD(or)

    static const auto lparen = x3::lit('(');
    static const auto rparen = x3::lit(')');

    // helper parsers
    static const auto keywords = kw_and | kw_or | lparen | rparen;
    static const auto word = x3::lexeme[+(x3::char_ - x3::ascii::space - lparen - rparen)];
    static const auto bareWord = word - keywords;
    static const auto quotedString = x3::lexeme[x3::char_('"') >> *(x3::char_ - '"') >> x3::char_('"')];

    DEFINE_RULE(Phrase,     quotedString | bareWord)
    DEFINE_RULE(Term,       ParenExpr | Phrase)
    DEFINE_RULE(ParenExpr,  lparen >> OrExpr >> rparen)
    template <ast::OPER Op>
    struct make_node
    {
        template <typename Context >
        void operator()(Context const& ctx) const
        {
            if (_attr(ctx).size() == 1)
                _val(ctx) = std::move(_attr(ctx)[0]);
            else
                _val(ctx) = ast::Expr{ Op, std::move(_attr(ctx)) };
        }
    };
    DEFINE_RULE(AndExpr,    (Term % kw_and)[make_node<ast::OPER_AND>{}])
    DEFINE_RULE(OrExpr,     (AndExpr % kw_or)[make_node<ast::OPER_OR>{}])
}

namespace burningmime::setmatch
{
    void parseRuleFluent(const char* buf)
    {
        ast::Node root;
        auto start = buf, end = start + strlen(buf);
        bool success = x3::phrase_parse(start, end, parser::OrExpr, x3::ascii::space, root);
        if (!success || start != end)
            throw std::runtime_error(std::string("Could not parse rule: ") + buf);
        printf("Result of parsing: %s\n=========================\n", start);
        boost::apply_visitor(ast::AstPrinter(), root);
    }
}

int main()
{
    burningmime::setmatch::parseRuleFluent(R"#("hello" and ("world" or "planet" or "globe"))#");
}
Result of parsing: 
=========================
And("hello", Or("world", "planet", "globe"))


Share : facebook icon twitter icon
How do you use a variable stored in a boost spirit closure as input to a boost spirit loop parser?

How do you use a variable stored in a boost spirit closure as input to a boost spirit loop parser?


By : knownbad
Date : March 29 2020, 07:55 AM
hope this fix your issue This is much easier with the new qi parser available in Spirit 2. The following code snippet provides a full example that mostly works. An unexpected character is being inserted into the final result.
code :
#include <iostream>
#include <string>

#include <boost/version.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_repeat.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

using boost::spirit::qi::repeat;
using boost::spirit::qi::uint_;
using boost::spirit::ascii::char_;
using boost::spirit::ascii::alpha;
using boost::spirit::qi::_1;
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;

template <typename P, typename T>
void test_parser_attr(
    char const* input, P const& p, T& attr, bool full_match = true)
{
    using boost::spirit::qi::parse;

    char const* f(input);
    char const* l(f + strlen(f));
    if (parse(f, l, p, attr) && (!full_match || (f == l)))
        std::cout << "ok" << std::endl;
    else
        std::cout << "fail" << std::endl;
}

static void
straight_forward()
{
    std::string str;
    int n;
    test_parser_attr("12\r\nTest Payload",
                     uint_[phx::ref(n) = _1] >> "\r\n" >> repeat(phx::ref(n))[char_],
                     str);
    std::cout << "str.length() == " << str.length() << std::endl;
    std::cout << n << "," << str << std::endl;  // will print "12,Test Payload"
}

template <typename P, typename T>
void
test_phrase_parser(char const* input, P const& p,
                   T& attr, bool full_match = true)
{
    using boost::spirit::qi::phrase_parse;
    using boost::spirit::qi::ascii::space;

    char const* f(input);
    char const* l(f + strlen(f));
    if (phrase_parse(f, l, p, space, attr) && (!full_match || (f == l)))
        std::cout << "ok" << std::endl;
    else
        std::cout << "fail" << std::endl;
}

template <typename Iterator>
struct test_grammar
    : qi::grammar<Iterator, std::string(), qi::locals<unsigned> > {

    test_grammar()
        : test_grammar::base_type(my_rule)
    {
        using boost::spirit::qi::_a;
        my_rule %= uint_[_a = _1] >> "\r\n" >> repeat(_a)[char_];
    }

    qi::rule<Iterator, std::string(), qi::locals<unsigned> > my_rule;
};

static void
with_grammar_local_variable()
{
    std::string str;
    test_phrase_parser("12\r\nTest Payload", test_grammar<const char*>(), str);
    std::cout << str << std::endl;  // will print "Test Payload"
}

int
main(int argc, char **argv)
{
    std::cout << "boost version: " << BOOST_LIB_VERSION << std::endl;

    straight_forward();
    with_grammar_local_variable();

    return 0;
}
Boost.Spirit.x3 avoid collapsing two consecutive attributes of the same type into a vector

Boost.Spirit.x3 avoid collapsing two consecutive attributes of the same type into a vector


By : rajeev
Date : March 29 2020, 07:55 AM
Any of those help The problem is that unlike character literals, x3::space has an attribute. So you don't have an attribute of two separate character sequences separated by whitespace, but rather an attribute of one big character sequence which includes the whitespace.
The omit directive is what you're after, and with that single addition your 'not working code' works. :-]
code :
// Example program
#include <string>
#include <iostream>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>

namespace x3 = boost::spirit::x3;

struct employee {
    std::string name;
    std::string location;
};
BOOST_FUSION_ADAPT_STRUCT(employee, name, location)

x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def
    =      +x3::ascii::alnum
        >>  x3::omit[+x3::space]
        >> +x3::ascii::alnum
    ;
BOOST_SPIRIT_DEFINE(parse_emp)

int main()
{
    std::string const input = "Joe Fairbanks";

    employee ret;
    x3::parse(input.begin(), input.end(), parse_emp, ret);

    std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << '\n';
}
Parsing nested lists with Boost.Spirit

Parsing nested lists with Boost.Spirit


By : Henry Alejandro Sant
Date : March 29 2020, 07:55 AM
will be helpful for those in need You're using auto for proto expression templates in the Qi domain - that's undefined behaviour 99.9% of the time:
undefined behaviour somewhere in boost::spirit::qi::phrase_parse
code :
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;

int main() {
    using It      = std::string::const_iterator;
    using Skipper = qi::space_type;

    for(std::string const input : { "[[\t1 , 2 ], [3, 4, 65.4]]", "[[\t1 , 2 ], [3, 4, 65.4], []]", "[]" })
    {
        std::cout << " ---- '" << input << "' ----\n";
        auto it = input.begin();

        //parse the string
        using doubles = std::vector<double>;
        using vectors = std::vector<doubles>;

        qi::rule<It, doubles(), Skipper> doubles_ = "[" >> -(qi::double_ % ",") >> "]";
        qi::rule<It, vectors(), Skipper> vectors_ = "[" >> -(doubles_    % ",") >> "]";

        vectors data;
        bool match = qi::phrase_parse(it, input.end(), vectors_, qi::space, data);

        //check if we have a match
        std::cout << "matched: " << std::boolalpha << match << '\n';
        if (it != input.end())
            std::cout << "unmatched part: " << std::string{it, input.end()} << '\n';

        //print the result
        std::cout << "result\n";
        for (const auto& v : data) {
            std::cout << "[";
            for (double i : v)
                std::cout << i << ",";
            std::cout << "]\n";
        }
    }
}
 ---- '[[   1 , 2 ], [3, 4, 65.4]]' ----
matched: true
result
[1,2,]
[3,4,65.4,]
 ---- '[[   1 , 2 ], [3, 4, 65.4], []]' ----
matched: true
result
[1,2,]
[3,4,65.4,]
[]
 ---- '[]' ----
matched: true
result
Boost-Spirit: Parsing lists into different fields of a struct

Boost-Spirit: Parsing lists into different fields of a struct


By : Joao Pimenta
Date : March 29 2020, 07:55 AM
I hope this helps you . I don't really like using semantic actions, but given the choice of AST and input, I don't think there's much of a choice.
I'd simplify the grammar:
code :
    rule  = '(' >> (int_[head_(_val, _1)] % ',') >> ')'
        >> '{' >> +(
                'X' >> int_[X_(_val, _1)]
              | 'Y' >> int_[Y_(_val, _1)]
              | 'Z' >> int_[Z_(_val, _1)]
          )
        >> '}';
template <std::vector<int> my_struct::*m> struct push {
    void operator()(my_struct& ms, int v) const { (ms.*m).push_back(v); }
};
px::function<push<&my_struct::head> > head_;
px::function<push<&my_struct::X> > X_;
px::function<push<&my_struct::Y> > Y_;
px::function<push<&my_struct::Z> > Z_;
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;

struct my_struct {
    std::vector<int> head;
    std::vector<int> X;
    std::vector<int> Y;
    std::vector<int> Z;
};

template<typename Iterator>
struct my_parser : qi::grammar<Iterator, my_struct()> {
    my_parser() : my_parser::base_type(start) {
        using namespace qi;
        using px::push_back;

        rule  = '(' >> (int_[head_(_val, _1)] % ',') >> ')'
            >> '{' >> +(
                    'X' >> int_[X_(_val, _1)]
                  | 'Y' >> int_[Y_(_val, _1)]
                  | 'Z' >> int_[Z_(_val, _1)]
              )
            >> '}';

        start = skip(space) [rule];
    }
  private:
    template <std::vector<int> my_struct::*m> struct push {
        void operator()(my_struct& ms, int v) const { (ms.*m).push_back(v); }
    };
    px::function<push<&my_struct::head> > head_;
    px::function<push<&my_struct::X> > X_;
    px::function<push<&my_struct::Y> > Y_;
    px::function<push<&my_struct::Z> > Z_;

    qi::rule<Iterator, my_struct()> start;
    qi::rule<Iterator, my_struct(), qi::space_type> rule;
};

int main() {
    using It = boost::spirit::istream_iterator;
    It f(std::cin >> std::noskipws), l;

    my_struct data;
    if (parse(f, l, my_parser<It>{}, data)) {
        std::cout << "Parsed:";
        std::copy(data.head.begin(), data.head.end(), std::ostream_iterator<int>(std::cout << "\nhead: ", " " ));
        std::copy(data.X.begin(), data.X.end(), std::ostream_iterator<int>(std::cout << "\nX: ", " " ));
        std::copy(data.Y.begin(), data.Y.end(), std::ostream_iterator<int>(std::cout << "\nY: ", " " ));
        std::copy(data.Z.begin(), data.Z.end(), std::ostream_iterator<int>(std::cout << "\nZ: ", " " ));
        std::cout << "\n";
    } else {
        std::cout << "Parse failed\n";
    }


    if (f != l)
        std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}
Parsed:
head: 111 222 333 
X: 231 54 
Y: 227 1112 
Z: 41156 
Remaining unparsed input: '
'
Boost::spirit attribute types not collapsing

Boost::spirit attribute types not collapsing


By : Harish
Date : March 29 2020, 07:55 AM
I hope this helps . This reminds me a lot of this infamous limitation:
Spirit Qi attribute propagation issue with single-member struct
Related Posts Related Posts :
  • C++ on Vistual Studio with CMake error: manifest 'build.ninja' still dirty after 100 tries
  • Is there a way to automatically resolve an overloaded method via a template parameter?
  • Fastest way to find pair in a vector, remove it while iterating
  • error C2440: '=': cannot convert from 'const char *' to 'LPCWSTR'
  • Unable to call boost::clear_vertex while using listS for the vertex and edge lists
  • Decoding binary data from serial port
  • Pattern to Implement an OO interface to a C program written in an imperative style
  • CEPH + Librados++ is not returning consisten results
  • `LoadLibraryExW` triggers exception `0xC0000023` from `NtMapViewOfSection`
  • static_cast to a struct type to access all of its member variable
  • Forward declaration for boost::intrusive_ptr class to reduce compile time
  • How to use priority_queue with a non-static compare method of class instance?
  • Template parameters inside and outside class/struct
  • Determining prime number
  • How to resolve ambiguity between constructors taking std::string and std::vector
  • My program crashes when I try to change private values from an object
  • Unordered_map with custom class as key
  • Strict aliasing rules broken with templates and inheritance
  • C++ Derived Class Override Return Type
  • singly linked list c++ constructor, destructor and printing out
  • How to clone class with vector of unique_ptr to base class
  • error: no match for operator
  • std::vector doesnt accept my struct as template
  • selection of people's contours
  • how to fix the (Error using mexOpenCV) on matlab?
  • Is or was there a proposal for c++ to use the context for short enum values?
  • Fair assumptions about std::hash implementations
  • undefined reference to libusb using cyusb
  • Function returns null pointer instead of address
  • C++17 copy elision and object destruction
  • Input multiple strings via operator>> c++
  • Avoiding overflow boost container
  • How to Write a Lambda Wrapping a Function with Optional Return Value
  • Partial specialization with more template parameters
  • How to convert fixed size array to pointer on pointer array
  • Memory leak in const member constructor with tag dispatching
  • C++ function with a generic and optional class
  • Custom QGraphicsItem That Contains Child QGraphicsItems
  • Are There Restrictions on What can be Passed to auto Template Parameters?
  • Rotating line inside rectangle bounds
  • Why do I need dynamic memory allocation if I can just create an array?
  • How can I convert a text file into a form that MPI_Bcast can send?
  • How to get array of all `this` of an instance
  • Using pointers as parameters
  • Automatic type deduction with const_cast is not working
  • Why does std::is_rvalue_reference not do what it is advertised to do?
  • Function Template Specialization with Forward Declared Type
  • template deduction failed in vector
  • Is there a signed `sizeof` alternative in Qt
  • clarification on overloading the -> operator
  • What is __m128d?
  • QtConcurrent: why releaseThread and reserveThread cause deadlock?
  • Function receiving different value than passed
  • Can C++ close a '''fstream''' variable after '''.close()'''?
  • Is it necessary to overload operator in this specific case
  • Comparing an element of a string array with a string
  • how to dereference a pointer of a map of pointers to objects in c++
  • How recursive function control flow change for static variable?
  • SDL 2 blitting BMP File
  • Why does an extremely large value cause this code to repeat infinitely?
  • shadow
    Privacy Policy - Terms - Contact Us © bighow.org