1
void Parse(string const& input)
{
    string::const_iterator begin = input.begin(), end = input.end();

    auto pin_parser    = qi::copy(+(qi::char_("a-z")));
    auto val_parser    = qi::copy(qi::float_ >> ':' >> *(qi::float_) >> ':' >> qi::float_);

    auto connect_parser = qi::copy( 
                                qi::lit("CONNECT") >> qi::space >> pin_parser[boost::phoenix::bind(callback, "PIN1", qi::_1)] >> qi::space
                                >> pin_parser[boost::phoenix::bind(callback, "PIN2", qi::_1)] >> qi::space
                                >> val_parser >> qi::space >> val_parser >> qi::space
                               );

    bool is_succ = qi::parse(begin, end, +connect_parser);
    std::cout << "Succ " << is_succ << std::endl;
}

I am trying to parse the following string using boost::spirit::qi.

CONNECT clk sda 1.020::1.030 0.200::0.00

CONNECT da doai 0.100::0.050 0.040::0.300

And then send the tokens parsed through callback. But getting following error. The compilation problem only comes when trying to parse long sequence. The compilation problem goes away if grammar sequence is shorter.

Say for example if i parse following, using the grammar below, then there is no compilation error.

CONNECT clk 0.200::0.00

CONNECT da 0.040::0.300

auto connect_parser = qi::copy(qi::lit("CONNECT") >> qi::space >> pin_parser[boost::phoenix::bind(callback, "PIN1", qi::_1)] >> qi::space
                                >> val_parser >> qi::space
                               );
spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l> >, 2l>&>, 1l>]'
PASDFParser.cpp:81:62:   required from here
/calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector/convert.hpp:27:13: error: invalid use of incomplete type 'struct boost::fusion::detail::barrier::as_vector<13>'
             type;
             ^
In file included from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector/detail/as_vector.hpp:15:0,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector/convert.hpp:11,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector.hpp:30,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/view/zip_view/detail/at_impl.hpp:12,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/view/zip_view/zip_view.hpp:19,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/view/zip_view.hpp:12,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/sequence/intrinsic/swap.hpp:15,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/sequence/intrinsic.hpp:23,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/include/intrinsic.hpp:11,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/proto/fusion.hpp:22,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/proto/core.hpp:21,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/proto/proto.hpp:12,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/support/meta_compiler.hpp:19,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/qi/meta_compiler.hpp:14,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/qi/action/action.hpp:14,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/qi/action.hpp:14,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/qi.hpp:14,
                 from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/include/qi.hpp:16,
                 from PASDFParser.h:17,
                 from PASDFParser.cpp:10:
/calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector/detail/cpp03/as_vector.hpp:28:12: note: declaration of 'struct boost::fusion::detail::barrier::as_vector<13>'
     struct as_vector;
sehe
  • 374,641
  • 47
  • 450
  • 633
Amit Dey
  • 131
  • 1
  • 1
  • 3

1 Answers1

0

By avoiding to define rules (instead using auto), you are pushing the limits of automatic attribute propagation and compatibility.

It doesn't help that you're explicit matching space characters with attributes. It will immediately help to qi::omit[] those. Although likely you just should consider using the appropriate skipper.

You can help the system just a tiny bit by telling it more about your intentions, it makes everything easier, e.g.:

auto pin_parser = copy(qi::as_string[+qi::char_("a-z")]);

Demonstration?

I couldn't really reproduce your issue after minimal cleanup. Of course I had to imagine a callback (I show a version that works regardless of whether as_string[] is applied);

Live On Coliru

#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>

void Parse(std::string_view input) {
    namespace qi = boost::spirit::qi;
    using boost::phoenix::bind;
    using qi::copy;
    using namespace qi::labels;
    auto begin = input.begin(), end = input.end();

    struct {
        void operator()(std::string_view name, std::vector<char> const& value) const {
            std::cout << name << ": " << quoted(std::string_view(value.data(), value.size()))
                      << " (vector)\n";
        }
        void operator()(std::string_view name, std::string_view value) const {
            std::cout << name << ": " << quoted(value) << " (string-like)\n";
        }
    } const callback;

    using qi::space;
    // auto space = qi::copy(qi::omit[+qi::space]);
    auto pin_parser = copy(+qi::char_("a-z"));
    //auto val_parser = copy(qi::lexeme[qi::float_ >> ':' >> *qi::float_ >> ':' >> qi::float_]);
    auto val_parser = copy(qi::float_ >> ':' >> *qi::float_ >> ':' >> qi::float_);

    auto connect_parser = copy(                            //
        "CONNECT" >> space                                 //
        >> pin_parser[bind(callback, "PIN1", _1)] >> space //
        >> pin_parser[bind(callback, "PIN2", _1)] >> space //
        >> val_parser >> space                             //
        >> val_parser >> space                             //
    );

    auto ok = qi::parse(begin, end, +connect_parser);
    std::cout << "Succ " << ok << std::endl;
}

int main() {
    for (
        auto input :
        {
            R"(CONNECT clk sda 1.020::1.030 0.200::0.00)",  // no trailing space
            R"(CONNECT da doai 0.100::0.050 0.040::0.300)", // no trailing space
            R"(CONNECT clk sda 1.020::1.030 0.200::0.00 )",
            R"(CONNECT da doai 0.100::0.050 0.040::0.300 )",
            R"(CONNECT clk sda 1.020::1.030 0.200::0.00 CONNECT da doai 0.100::0.050 0.040::0.300)", // no trailing space
            R"(CONNECT clk sda 1.020::1.030 0.200::0.00
               CONNECT da doai 0.100::0.050 0.040::0.300)",
        }) //
    {
        Parse(input);
    }
}

Prints

PIN1: "clk" (vector)
PIN2: "sda" (vector)
Succ 0
PIN1: "da" (vector)
PIN2: "doai" (vector)
Succ 0
PIN1: "clk" (vector)
PIN2: "sda" (vector)
Succ 1
PIN1: "da" (vector)
PIN2: "doai" (vector)
Succ 1
PIN1: "clk" (vector)
PIN2: "sda" (vector)
PIN1: "da" (vector)
PIN2: "doai" (vector)
Succ 1
PIN1: "clk" (vector)
PIN2: "sda" (vector)
Succ 1

Problem #1: Semantic Actions

The Succ 0 lines betray a problem: the semantic actions run even when the parse is not successful. See Boost Spirit: "Semantic actions are evil"?

Alternatively, using a skipper allows absense of non-mandatory whitespace:

auto pin_parser = copy(qi::as_string[qi::lexeme[+qi::char_("a-z")]]);
auto val_parser = copy(qi::lexeme[qi::float_ >> ':' >> *qi::float_ >> ':' >> qi::float_]);

auto connect_parser = copy(                   //
    "CONNECT"                                 //
    >> pin_parser[bind(callback, "PIN1", _1)] //
    >> pin_parser[bind(callback, "PIN2", _1)] //
    >> val_parser                             //
    >> val_parser                             //
);

auto ok = qi::phrase_parse(begin, end, +connect_parser, qi::space);

Prints Live On Coliru:

PIN1: "clk" (string-like)
PIN2: "sda" (string-like)
Succ 1
PIN1: "da" (string-like)
PIN2: "doai" (string-like)
Succ 1
PIN1: "clk" (string-like)
PIN2: "sda" (string-like)
Succ 1
PIN1: "da" (string-like)
PIN2: "doai" (string-like)
Succ 1
PIN1: "clk" (string-like)
PIN2: "sda" (string-like)
PIN1: "da" (string-like)
PIN2: "doai" (string-like)
Succ 1
PIN1: "clk" (string-like)
PIN2: "sda" (string-like)
PIN1: "da" (string-like)
PIN2: "doai" (string-like)
Succ 1

Fixing The Semantic Actions

To fix the problem with the semantic action firing for incomplete/failing (branch) parses you would build the entire result, at least until you know the rule doesn't fail or get backtracked:

auto connect_parser =
    qi::copy("CONNECT" >> pin_parser >> pin_parser >> val_parser >> val_parser);

px::function callback = [](std::string_view pin1, std::string_view pin2) {
    std::cout << "pin1: " << quoted(pin1) << ", pin2: " << pin2 << "\n";
};

auto ok = qi::phrase_parse(begin, end, +connect_parser[callback(_1, _2)], qi::space);

See it Live

Rules, No Semantic Actions

At this rate, we might just as well use rules, which will allow us to have implicit lexemes (Boost spirit skipper issues) and not needing qi::omit[], qi::lexeme[], qi::copy, qi::as_string[] or other type coercion hints:

Live On Coliru

#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>

using Pin  = std::string;
using Pins = std::pair<Pin, Pin>;

std::vector<Pins> Parse(std::string_view input) {
    namespace qi = boost::spirit::qi;
    using It     = std::string_view::const_iterator;

    qi::rule<It, Pin()> pin_parser = +qi::alpha;
    qi::rule<It>        val_parser = qi::float_ >> ':' >> *qi::float_ >> ':' >> qi::float_;
    qi::rule<It, Pins(), qi::space_type> connect_parser =
        "CONNECT" >> pin_parser >> pin_parser >> val_parser >> val_parser;

    auto begin = input.begin(), end = input.end();
    std::vector<Pins> data;
    qi::phrase_parse(begin, end, +connect_parser > qi::eoi, qi::space, data);
    return data;
}

#include <fmt/ranges.h>
int main() {
    for (
        auto input :
        {
            R"(CONNECT clk sda 1.020::1.030 0.200::0.00)",
            R"(CONNECT da doai 0.100::0.050 0.040::0.300)",
            R"(CONNECT clk sda 1.020::1.030 0.200::0.00 )",
            R"(CONNECT da doai 0.100::0.050 0.040::0.300 )",
            R"(CONNECT clk sda 1.020::1.030 0.200::0.00 CONNECT da doai 0.100::0.050 0.040::0.300)", // no trailing space
            R"(CONNECT clk sda 1.020::1.030 0.200::0.00
               CONNECT da doai 0.100::0.050 0.040::0.300)",
        }) //
    {
        fmt::print("{} -> {}\n", input, Parse(input));
    }
}

Prints

CONNECT clk sda 1.020::1.030 0.200::0.00 -> [("clk", "sda")]
CONNECT da doai 0.100::0.050 0.040::0.300 -> [("da", "doai")]
CONNECT clk sda 1.020::1.030 0.200::0.00  -> [("clk", "sda")]
CONNECT da doai 0.100::0.050 0.040::0.300  -> [("da", "doai")]
CONNECT clk sda 1.020::1.030 0.200::0.00 CONNECT da doai 0.100::0.050 0.040::0.300 -> [("clk", "sda"), ("da", "doai")]
CONNECT clk sda 1.020::1.030 0.200::0.00
               CONNECT da doai 0.100::0.050 0.040::0.300 -> [("clk", "sda"), ("da", "doai")]
sehe
  • 374,641
  • 47
  • 450
  • 633