1

This is in continuation of my question mentioned here

Inconsistent Generator directive column behavior in boost karma

I want to wrap that rule into another rule and when doing so , pass the column directive to the child rule but I cannot figure out what's the right way of doing that.

Here is the code below

#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/struct.hpp>
#include <boost/fusion/include/nview.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace client
{


struct BoxData
{
    int num;
    std::string datatype;
    std::string dataname;
    std::string inputicon;
};

struct Box
{
    std::vector<BoxData> box_data;
};

typedef std::back_insert_iterator<std::string> iterator_type;
}

BOOST_FUSION_ADAPT_STRUCT(
        client::BoxData,
//      (int, num)
        (std::string, datatype)
        (std::string, dataname)
        (std::string, inputicon)
)

BOOST_FUSION_ADAPT_STRUCT(
        client::Box,
        (std::vector<client::BoxData>, box_data)
)


///////////////////////////////////////////////////////////////////////////////
int main()
{
    // some employees
    std::vector<client::BoxData> const employees{
            {25, "int",    "sra_command", "fa fa-wrench"},
            {26, "float",  "swt_command", "fa fa-wrench"},
            {27, "double", "msc_command", "fa fa-mobile"},
            {28, "int",    "sra_command", "fa fa-wrench"},
            {29, "float",  "swt_command", "fa fa-wrench"},
            {30, "double", "msc_command", "fa fa-mobile"},
            {31, "int",    "sra_command", "fa fa-wrench"},
            {32, "float",  "swt_command", "fa fa-wrench"},
            {33, "double", "msc_command", "fa fa-mobile"},
    };

    client::Box box;
    ///TODO prevent copying of the vector
    box.box_data = employees;

    // now print them all
    std::string generated;
    {
        using namespace boost::spirit::karma;

        using Sink = client::iterator_type;
        using BoxDataAttr = client::BoxData;
        using BoxAttr = client::Box;

        rule<Sink, BoxDataAttr(),space_type> small_box = "<B>" << string << "<1>" << string << "<2>" << string << "<3>";

        rule<Sink , BoxAttr()> big_box = "<Start>" << *small_box << "<End>" ;

        generate(Sink(generated),[big_box],box);
    }

    std::cout << generated << std::endl;
}

In the line

rule<Sink , BoxAttr()> big_box = "<Start>" << *small_box << "<End>" ;

I want to pass the

columns(2, "delimiter\n")[small_box]

delimiter so that the column delimiter is applied to the small_box rule.

So the expected output becomes

<Start><B>int<1>sra_command<2>fa fa-wrench<3><B>float<1>swt_command<2>fa fa-wrench<3>delimiter
<B>double<1>msc_command<2>fa fa-mobile<3><B>int<1>sra_command<2>fa fa-wrench<3>delimiter
<B>float<1>swt_command<2>fa fa-wrench<3><B>double<1>msc_command<2>fa fa-mobile<3>delimiter
<B>int<1>sra_command<2>fa fa-wrench<3><B>float<1>swt_command<2>fa fa-wrench<3>delimiter
<B>double<1>msc_command<2>fa fa-mobile<3>delimiter<End>

Eventually since there would be vector which would pass another custom delimiter to the big_box rule.

Background

I am planning to write a diagnostic interface as an exercise for learning various C++ concepts which involves the following.

1.Parsing data from an IDL file .I haven't defined the exact format yet but will look something similar to this

struct Data1
{
int command_one output "fa fa-wrench";
float commmand_two output "fa fa-sensor";
}

struct Data2
{
bool a input switch;
int b input progress_bar {0,100} ;
}
  1. Generating HTML elements from the IDL file. Each struct is wrapped in a box which contains the individual elements inside them in smaller boxes with their icons/optional parts. The nth delimiter is useful for generating the bootstrap grid for placement of these boxes on the screen.

  2. Complete the HTML page with a websocket implementation that updates DOM elements automatically when JSON data is received containing DOM element name -value pair . Similarly for each input , a send command is implemented to wrap it in a JSON and send to the web server.

  3. Auto generate the code for the webserver so that the only code left to implement is receiving/transmitting data from an external source with all conversions to/from JSON generated.

The following use case prompted me to look for a parser/generator solution.

Community
  • 1
  • 1
user48833
  • 35
  • 4
  • Regarding the added background, I'm going to state that it will be an order of magnitude easier to just implement directly on top of Fusion for the generation side of things. It can give you the "reflection" parts of it, which you can use to drive regular generic programming. – sehe May 02 '17 at 13:50
  • Regarding data-structure driven generation, also look at https://github.com/cierelabs/boostache for such inspiration. Regarding template-expansion style generation (HTML) also look at libraries like http://stackoverflow.com/questions/2548075/c-string-template-library – sehe May 02 '17 at 13:52
  • Finally, look at libraries like protobuf+grpc for inspiration regarding (JSON) rpc calls and service generated from service-definitions. I know you are in it for the exercise, but good exercise starts with planning and looking at existing knowledge :) – sehe May 02 '17 at 13:54
  • thanks for the feedback. I will definitely look into them. I was planning on using apache thrift for RCP class and services but this looks even better. I have to plan my project better before actually working on it :) – user48833 May 02 '17 at 14:24

1 Answers1

2

I'm not too sure about the cause for your question, but it seems to me the solution from yesterday holds:

Live On Coliru

    rule<Sink, BoxDataAttr()> small_box = "<B>" << string << "<1>" << string << "<2>" << string << "<3>";

    rule<Sink, BoxAttr()> big_box = "<Start>" << columns(4, "delimiter\n") [small_box % eol] << "<End>" ;

    generate(Sink(generated), big_box, employees);

Prints

<Start><B>int<1>sra_command<2>fa fa-wrench<3>
<B>float<1>swt_command<2>fa fa-wrench<3>
delimiter
<B>double<1>msc_command<2>fa fa-mobile<3>
<B>int<1>sra_command<2>fa fa-wrench<3>
delimiter
<B>float<1>swt_command<2>fa fa-wrench<3>
<B>double<1>msc_command<2>fa fa-mobile<3>
delimiter
<B>int<1>sra_command<2>fa fa-wrench<3>
<B>float<1>swt_command<2>fa fa-wrench<3>
delimiter
<B>double<1>msc_command<2>fa fa-mobile<3>delimiter
<End>

On a hunch, you might have missed the fact that you had , space_type as the delimiter on the small_box rule.

Eventually since there would be vector which would pass another custom delimiter to the big_box rule.

At this point I question your choice of tools. Why not roll your own pretty-printing here. I expect it to be considerably simpler. Also read up on https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem

Bonus:

Here's avoiding copying the vector:

client::Box const employees { {
        {25, "int",    "sra_command", "fa fa-wrench"},
        {26, "float",  "swt_command", "fa fa-wrench"},
        {27, "double", "msc_command", "fa fa-mobile"},
        {28, "int",    "sra_command", "fa fa-wrench"},
        {29, "float",  "swt_command", "fa fa-wrench"},
        {30, "double", "msc_command", "fa fa-mobile"},
        {31, "int",    "sra_command", "fa fa-wrench"},
        {32, "float",  "swt_command", "fa fa-wrench"},
        {33, "double", "msc_command", "fa fa-mobile"},
} };

More generally, move semantics could have served:

box.box_data = std::move(employees);
sehe
  • 374,641
  • 47
  • 450
  • 633