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