References get lost coming out of parser.

Dan Bloomquist <[email protected]> Sun, 24 Nov 2019 18:05:08 -0800
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
Hi Henri, all,
I'm pretty close to just detailing this. And I'm sorry Henri, I didn't 
use your lambdas in the last post, I have them in there now.

I've traced as much as I can make sense of it but still don't know why 
some of my references get lost. I can trace into the 'op_parser' and the 
op container builds up just fine adding the six ops for testing. The 
'funct_op' reference looks good where ever I can see it. But when the 
parser is done some of the 'funct_op' references are set with 0xcccccccc.
* 0xCCCCCCCC : Used by Microsoft's C++ debugging runtime library to mark 
uninitialised stack memory
The 'push_op' lambda is the one that gets messed and it is the one that 
comes from op_type_ :symbols<rpn::funct_op>. So I'm pretty sure that 
even if I pass it references, it is making copies that disappear. I 
tried symbols<rpn::funct_op&> but that cryptically fails to compile. I'm 
sure there is a way to get symbols to work with a reference, or, at 
least, I'm hoping!

Thanks, Dan.


// .............................

#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <functional>
#include <variant>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>

namespace rpn { // ...............................................
     //just enough for this test, no assert or checking here, using 
'get' instead of 'visit'........
     // see: https://github.com/lakeweb/stuff/blob/master/void_method2.cpp
     using rpn_val = std::variant<std::monostate, int, std::string>;
     using rpn_stack_type = std::vector<rpn_val>;

     struct rpn_stack {
         rpn_stack_type stack;
         rpn_val& top(size_t pos = 0) {
             if (pos >= stack.size())throw(std::exception("Stack too 
small for top index"));
             return *(stack.end() - pos - 1);
         }
         void push(rpn_val val) { stack.push_back(val); }
         void pop() { stack.erase(stack.end() - 1); }
         size_t size() const { return stack.size(); }
         void clear() { stack.clear(); }
     };
     using funct_op = void(*)(rpn_stack&, void* ptr);
     struct rpn_op {
         rpn_stack& stack;
         funct_op& funct;
         rpn_val val;
         void* ptr;
         rpn_op operator =(const rpn_op& op) { return *this = op; }
         rpn_op(rpn_stack& stack, funct_op& funct, void* ptr = nullptr) 
:stack(stack), funct(funct), ptr(ptr), val(std::monostate()) {}
         rpn_op(rpn_stack& stack, funct_op& funct, rpn_val& val) 
:stack(stack), funct(funct), val(val), ptr(this) {}
         rpn_op(const rpn_op& ov) :stack(ov.stack), funct(ov.funct), 
val(ov.val), ptr(ov.ptr) { if (val.index()) ptr = this; }
         void operator ()() { funct(stack, ptr); }
     };
     struct rpn_ops {
         using rpn_ops_type = std::vector<rpn_op>;
         using iterator = rpn_ops_type::iterator;
         using value_type = rpn_op;
         rpn_stack& stack;
         rpn_ops_type ops;
         rpn_ops(rpn_stack& stack) :stack(stack) {}
         void add_op(funct_op& funct, void* ptr = nullptr) { 
ops.push_back(rpn_op(stack, funct, ptr)); }
         void add_op_var(funct_op& funct, rpn_val var) { 
ops.push_back(rpn_op(stack, funct, var)); }
         void add_op(const char* name, void* ptr = nullptr);
         void add_op_var(const char* name, rpn_val var);

         iterator begin() { return ops.begin(); }
         iterator end() { return ops.end(); }
         void clear() { ops.clear(); }
     };
     static funct_op push = [](rpn_stack& stack, void* ptr) {auto test = 
static_cast<rpn_op*>(ptr); stack.push(static_cast<rpn_op*>(ptr)->val); };
     static funct_op add = [](rpn_stack& stack, void* ptr) 
{std::get<1>(stack.top(1)) += std::get<1>(stack.top()); stack.pop(); };
     struct var_print_cout {
         void operator()(const std::monostate& item) { std::cout << 
"variant is null" << '\n'; }
         void operator()(const int& item) { std::cout << "int:     " << 
item << '\n'; }
         void operator()(const std::string& item) { std::cout << "str: " 
<< item << '\n'; }
     };
     static funct_op print = [](rpn_stack& stack, void* ptr) 
{std::visit(rpn::var_print_cout(), stack.top()); stack.pop(); };

}///rpn namespace

const rpn::funct_op dummy = [](rpn::rpn_stack& stack, void* target) {};
static struct rpn_names_type {
     const std::string name;
     const rpn::funct_op& op;
     //rpn::check_op& check;
}rpn_names[] = {
     {"add", rpn::add },
     {"push", rpn::push },
     {"print", rpn::print},
     {"noop", dummy},
};
static rpn_names_type* rpn_names_end = rpn_names + sizeof(rpn_names) / 
(sizeof(rpn_names_type) + 1);

// ................
//Tab Types according to Riched20 ... abbreviated for this test
#define PFA_TAB_LEFT        0
#define PFA_TAB_CENTER        1
#define PFA_TAB_RIGHT        2
#define PFA_TAB_DECIMAL        3
#define PFA_TABBASEMASK        0x00ffffff

struct Tabs {
     using value_type = int;
     using tabs_type = std::vector<value_type>;
     using iterator = tabs_type::iterator;
     tabs_type tabs;
     void insert(iterator where, iterator first, iterator last) { 
tabs.insert(where, first, last); }
     void insert(iterator where, const value_type& val) { 
tabs.insert(where, val); }
     iterator begin() { return tabs.begin(); }
     iterator end() { return tabs.end(); }
};

struct font {
     std::string face_name;
     size_t point = 0;
     bool bold = false;
     bool italic = false;
     bool strike = false;
     size_t id = 0;
};

struct rpt_header_item {
     std::string text;
     size_t tab_pos;
     bool angle = false;
};
BOOST_FUSION_ADAPT_STRUCT(rpt_header_item, tab_pos, angle)
using rpt_header_set_type = std::vector<rpt_header_item>;

struct rpt_headers_set {
     using iterator = rpt_header_set_type::iterator;
     using value_type = rpt_header_item;//for x3
     rpt_header_set_type set;
     Tabs tabs;
     size_t size() { return set.size(); }
     void insert(iterator, const rpt_header_item& hdr) { 
set.push_back(hdr); }
     void push_back(const rpt_header_item& hdr) { set.push_back(hdr); }
     iterator begin() { return set.begin(); }
     iterator end() { return set.end(); }
     //void set_metric(LPRECT rect, CDC* pDC) { tabs.set_metric(rect, 
pDC); }
};

//for one attribute criterion
struct composition {
     composition(font& af, rpt_headers_set& hs, rpn::rpn_ops& ops) 
:afont(af), hset(hs), ops(ops) {}
     std::string name;
     Tabs tabs; //for now.......
     font& afont;
     rpt_headers_set& hset;
     rpn::rpn_ops& ops;
};

namespace parsers {
     using namespace boost::spirit::x3;

     auto set_bool = [](auto at, auto def) {
         auto propagate = [at](auto ctx) {
             traits::move_to(_attr(ctx), _val(ctx).*(at)); };
         return ('=' >> bool_[propagate]) | attr(def)[propagate];
     };
     auto set_val = [](auto member, auto p) {
         auto propagate = [member](auto& ctx) {
             traits::move_to(_attr(ctx), _val(ctx).*(member));
         };
         return as_parser(-lit('=') >> p)[propagate];
     };
     auto const words = lexeme[+char_("a-zA-Z ")];
     auto const quoted_words = '"' >> words >> '"';

     auto const font_parser = boost::spirit::x3::rule<class _, font>{ 
"font" } = [] {
         return set_val(&font::face_name, words)
             >> *(',' >> (
                 lit("size") >> set_val(&font::point, int_)
                 | lit("bold") >> set_bool(&font::bold, true)
                 | lit("italic") >> set_bool(&font::italic, true)
                 | lit("strike") >> set_bool(&font::strike, true)
                 )
                 ) >> ')';
     }();
     auto const htext = [](auto& ctx) { _val(ctx).text += '\t' + 
_attr(ctx); };
     auto const header_parser = boost::spirit::x3::rule<class _, 
rpt_header_item>{ "header" } = [] {
         return *(quoted_words[htext] % ',')
             >> *(',' >> (
                 lit("tab") >> set_val(&rpt_header_item::tab_pos, int_)
                 | lit("angle") >> set_bool(&rpt_header_item::angle, true)
                 )
                 ) >> ')';
     }();
     auto const header_set_parser = rule<class _, 
rpt_headers_set>("header_set") = [] {
         return *(lit("item") >> '(' >> header_parser);
     }();
     auto const tab_parser = rule<class _, Tabs>("Tabs") = [] {
         Tabs::value_type tab_state;
         struct tab_type_ : symbols<Tabs::value_type>{ tab_type_(){ add
                 ("L", PFA_TAB_LEFT << 24)
                 ("R", PFA_TAB_RIGHT << 24)
                 ("C", PFA_TAB_CENTER << 24);}
         } tab_type;
         auto const type = [&tab_state](auto& ctx) {tab_state = 
_attr(ctx); };
         auto const val = [&tab_state](auto& ctx) {tab_state|= 
_attr(ctx); };
         auto const push = [&tab_state](auto& ctx) 
{_val(ctx).insert(_val(ctx).end(),tab_state); };
         auto const pt = -lit(',') >> tab_type[type] >> int_[val];
         return *pt[push] >> ')';
     }();
     auto const op_parser = rule<class _, rpn::rpn_ops>("rpn_operators") 
= [] {
         struct op_type_ :symbols<rpn::funct_op> {} op_type;
         std::for_each(rpn_names, rpn_names_end, 
[&op_type](rpn_names_type& op) {op_type.add(op.name, op.op); });
         auto const push_op = [](auto& ctx) 
{_val(ctx).add_op(_attr(ctx)); };
         auto const push_val = [](auto& ctx) 
{_val(ctx).add_op_var(rpn::push, _attr(ctx)); };
         return *( -lit(',') >> (op_type[push_op] | (int_[push_val] | 
quoted_words[push_val])));
     }();
     struct comp_parser : parser<comp_parser> {
         comp_parser() {}
         template<typename Iterator, typename Context, typename 
RContext, typename Attribute>
         bool parse(Iterator& first, Iterator const& last, Context 
const& context,
             RContext const& rcontext, Attribute& attr_) const
         {
             composition& attr = attr_;//for intelesense
             //skip_over(first, last, context);
             unused_type unused{};
             auto parse = [&first,last](auto parser, auto& attr) {return 
phrase_parse(first, last, parser, space, attr); };
             Iterator save = first;
             //the report sectionand name will not accually be handled 
in this parser
             parse(lit("report_section") >> words, attr.name);
             parse(lit("tabs(") >> tab_parser, attr.tabs);
             parse(lit("headers") >> *(lit("item") >> '(' >> 
header_parser), attr.hset);
             parse(lit("component") >> "op" >> '(' >> op_parser, attr.ops);

             return true;
         }
     };
}
auto const the_parse = parsers::comp_parser{};

//test and print............
std::ostream& operator << (std::ostream& os, /*const*/ font& afont) {
     return os << '\n' << std::boolalpha
         << "face_name = " << afont.face_name << '\n'
         << "point     = " << afont.point << '\n'
         << "bold      = " << afont.bold << '\n'
         << "italic    = " << afont.italic << '\n'
         << "strike    = " << afont.strike << '\n';
}
std::ostream& operator << (std::ostream& os, /*const*/ rpt_header_item& 
hdr) {
     std::replace(hdr.text.begin(), hdr.text.end(), '\t', '*');
     return os << '\n' << std::boolalpha
         << "text    = " << hdr.text << '\n'
         << "tab     = " << hdr.tab_pos << '\n'
         << "angle   = " << hdr.angle << '\n';
}
std::ostream& operator << (std::ostream& os, /*const*/ rpt_headers_set& 
hdrs) {
     for (auto& item : hdrs)
         os << item;
     return os;
}
std::ostream& operator << (std::ostream& os, /*const*/ composition& comp) {
     return os << comp.afont << comp.hset << std::endl;
}
std::ostream& operator << (std::ostream& os, /*const*/ Tabs& tabs) {
     for (auto& tab : tabs)
         std::cout << (tab >> 24) << " - " << (PFA_TABBASEMASK & tab) << 
"; ";
     return os << std::endl;
}
std::ostream& operator << (std::ostream& os, /*const*/ rpn::rpn_ops& comp) {
     return os;
}
template<typename P, typename A>
bool test_parse(std::string in, P parser, A& attr) {
     std::cout << "testing:\n" << in << std::endl;
     auto begin(in.begin());
     bool r = phrase_parse(begin, in.end(), parser, 
boost::spirit::x3::space, attr);
     std::cout << attr << std::endl;
     return r;
}

// .............
const char* some_section = R";(
report_section the report section name
     tabs(L1000 R2000,C3500,L5000)
     headers
         item("Description","an other", tab=1000)
         item("the next one",tab=2000,angle)
     component
         op(5,6,add,print,"print text",print)
     catgroup
         print_at(3,"another test")

report_section the next section name
         font(Times New Roman, bold, size=12)
...
);";

int main() {
     using namespace parsers;
     {
         std::cout << "*****************testing the big 
one!********************\n";
         rpt_headers_set hs;
         font bfont;
         rpn::rpn_stack stack;
         rpn::rpn_ops ops(stack);
         composition comp(bfont, hs, ops);
         test_parse(some_section, the_parse, comp);
         //this runs the rpn engine
         std::cout << "\nprinting the rpn operators\n";
         for (auto& op : ops)
             op();
     }
     Tabs tabs;
//    test_parse("tabs(L1000 R2000,C3500 L5000)", "tabs(" >> tab_parser, 
tabs);

     rpt_header_item hitem;
     //test_parse("text(\"A Single\", \"Header\", tab = 500)", "text(" 
 >> header_parser, hitem);

     rpt_headers_set headers;
     //test_parse(some_section, "headers" >> *("text(" >> 
header_parser), headers);

     //test_parse(some_section, lit("headers") >> header_set_parser, 
headers);

     font afont;
//    test_parse("font(Times New Roman, italic, size=12, bold=false, 
strike=true)", "font(" >> font_parser, afont);

     return 0;
}




_______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general