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 8907501
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 15, 20262026-06-15T02:55:57+00:00 2026-06-15T02:55:57+00:00

I have a simple parser which can parse lists of ints or quoted strings.

  • 0

I have a simple parser which can parse lists of ints or quoted strings.

If I do the SIMPLE_CASE where I take the input to be:

std::string input1 = "{ INT: 42, 24 STR: \"Smith\", \"John\" }";

it parses correctly into my_record, which contains a list of ints and a list of std::string.

I want to modify this code to be generic so that it can take zero or more INT lists and zero or more STR lists in arbitrary order and stuff them into my_record in the proper order. I would like my second, more generic test case:

std::string input1 = "{ STR: \"Joe\" INT: 42, 24 STR: \"Smith\", \"John\" }";

to parse as:

client::my_record expected1 { { 42, 24 }, {"Joe", "Smith", "John"} }; 

The code below works fine if I run:

/tmp$ g++ -DSIMPLE_CASE -g -std=c++11 sandbox.cpp -o sandbox && ./sandbox 

but I’m not sure how to get the general case to work when running this:

/tmp$ g++ -g -std=c++11 sandbox.cpp -o sandbox && ./sandbox 

Code for sandbox.cpp

#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_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

#include <string>
#include <complex>
#include <algorithm>

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

    struct my_record
    {
        std::vector<int>          m_ints;
        std::vector<std::string>  m_strs;

        bool operator==( const my_record& other ) const
        {
            return std::equal( m_ints.begin(), m_ints.end(), other.m_ints.begin() )
                && std::equal( m_strs.begin(), m_strs.end(), other.m_strs.begin() );
        }
        bool operator!=( const my_record& other ) const
        {
            return ! operator==( other );
        }
        friend std::ostream& operator<<( std::ostream& os, const my_record& rec );
    };

    std::ostream& operator<<( std::ostream& os, const my_record& rec )
    {
        for( const auto& x : rec.m_ints )
            std::cerr << x << ' ';
        std::cerr << std::endl;

        for( const auto& x : rec.m_strs )
            std::cerr << x << ' ';
        std::cerr << std::endl;

    }
}

BOOST_FUSION_ADAPT_STRUCT(
    client::my_record,
        (std::vector<int>,          m_ints)
        (std::vector<std::string>,  m_strs)
)

namespace client
{
    template <typename Iterator>
    struct employee_parser : qi::grammar<Iterator, my_record(), ascii::space_type>
    {
        employee_parser() : employee_parser::base_type(start)
    {
        using qi::int_;
        using qi::lit;
        using qi::double_;
        using qi::lexeme;
        using ascii::char_;

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

#ifdef SIMPLE_CASE
        start %=
            '{'
            >>  int_list
            >>  str_list
            >>  '}'
            ;
#else
        // not sure how to approach this
        start %=
            '{'
            >>  *(int_list)  // want zero or more of these, in any order
            >>  *(str_list)  // want zero or more of these, in any order
            >>  '}'
            ;
#endif

        str_list %=
                lit( "STR:" ) >> quoted_string % ','    
                ;

        int_list %=
                lit( "INT:" ) >> int_ % ','
                ;
    }

    qi::rule<Iterator, std::string(), ascii::space_type>               quoted_string;
    qi::rule<Iterator, std::vector<std::string>(), ascii::space_type>  str_list;
    qi::rule<Iterator, std::vector<int>(),         ascii::space_type>  int_list;

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

static int 
TryParse( const std::string& input, const client::my_record& expected )
{
    using boost::spirit::ascii::space;
    client::my_record                        rec;
    auto                                     iter = input.begin(), end = input.end();
    client::employee_parser<decltype(iter)>  g;
    phrase_parse( iter, end, g, space, rec );
    if ( iter!=end )
    {
        std::cerr << "failed to parse completely" << std::endl;
        return -1;
    } else if ( rec!=expected ) {
        std::cerr << "unexpected result in parse" << std::endl;
        std::cerr << rec;
        return -1;
    }
    return 0;
}

int 
main(int argc, char* argv[])
{
#ifdef SIMPLE_CASE
    client::my_record  expected1 { { 42, 24 }, {"Smith", "John"} }, emp;
    std::string        input1 = "{ INT: 42, 24 STR: \"Smith\", \"John\" }";
    return TryParse( input1, expected1 );
#else
    client::my_record  expected1 { { 42, 24 }, {"Joe", "Smith", "John"} }, emp;
    std::string        input1 = "{ STR: \"Joe\" INT: 42, 24 STR: \"Smith\", \"John\" }";
    return TryParse( input1, expected1 );
#endif

}
  • 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-15T02:55:58+00:00Added an answer on June 15, 2026 at 2:55 am

    You grammar is wrong,

        start %=
            '{'
            >>  *(int_list)  // want zero or more of these, in any order
            >>  *(str_list)  // want zero or more of these, in any order
            >>  '}'
            ;
    

    This means accept any number of ints followed by any number of string. You can no have int, string, int, or any other combination.

    You need something like

        start %=
            '{'
             >> *( int_list  // want zero or more of these, in any order
                 | str_list  // want zero or more of these, in any order
                 )
            >>  
            '}'
            ;
    

    But obviously you need to plum that into you data structure, bewarned you may have to use semantic actions.

    ALSO:

    whilst I am here, I can’t let this slide:

        std::ostream& operator<<( std::ostream& os, const my_record& rec )
        {
            for( const auto& x : rec.m_ints )
                std::cerr << x << ' ';
            std::cerr << std::endl;
    
            for( const auto& x : rec.m_strs )
                std::cerr << x << ' ';
            std::cerr << std::endl;
    
        }
    

    should be straeming to os like:

            for( const auto& x : rec.m_ints )
                os << x << ' ';
            os << '\n';
    

    Also try and avoid endling in stream insertion operator, use \n if you need a new line.

    THE SOLUTION:

    What was need in the end was to use phoenix functions, push_back and a binder.

    template<typename Iterator>
    struct my_grammar 
    : qi::grammar<Iterator, my_record(), ascii::space_type> {
    
        my_grammar() 
        : my_grammar::base_type(start) {
    
            quoted_string %= qi::lexeme['"' >> +(qi::char_ - '"') >> '"'];
    
            start = qi::lit("{")
                    >>
                    *( "INT:" >> qi::int_     
                        [ 
                            phx::push_back(
                                phx::at_c<0>(
                                    qi::_val
                                ), 
                                qi::_1
                            ) 
                        ] % ","
                     | "STR:" >> quoted_string
                         [ 
                            phx::push_back(
                                phx::bind(
                                    &my_record::m_strs,
                                    qi::_val
                                ), 
                                qi::_1
                            ) 
                        ] % ","
                     )
                    >> 
                    "}"
                     ;
        }
        qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
        qi::rule<Iterator, my_record(),   ascii::space_type>   start;
    };
    

    The whole code listing can be seen here:

    http://ideone.com/XW18Z2

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

In my google maps program I have simple KML parser which retrieve only coordinates
I have JSON data which contents Strings and Image URLs, and I already parse
I have a simple web app which lists a private group of people and
I have to develop a simple parser, to read block of text for example:
I have the following methods in my simple Custom Parser Class, when I execute
I have started working on a simple XML pull-parser, and as I've just defuzzed
New to Python, have a simple, situational question: Trying to use BeautifulSoup to parse
I have written a simple C++ shell program to parse large XML files and
I'm writing a simple eclipse plugin, which is a code generator. User can choose
I have implemented combinatorial GLR parsers. Among them there are: char(·) parser which consumes

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.