I am trying to parse this netlist from a .net file:
V1 N001 N002 10
R1 N001 N002 24.9
I have the following structs:
struct ElementStatement {
boost::optional<std::string> element_label;
boost::optional<std::string> element_node1;
boost::optional<std::string> element_node2;
boost::optional<double> element_value;
};
struct SpiceNetlist {
std::vector<ElementStatement> element_statements;
//to be expanded
};
This is my code in the .cpp file to parse and print out the parsed variables:
BOOST_FUSION_ADAPT_STRUCT(ElementStatement, element_label, element_node1,
element_node2, element_value)
BOOST_FUSION_ADAPT_STRUCT(SpiceNetlist, element_statements)
namespace qi = boost::spirit::qi;
class SpiceGrammar
: public boost::spirit::qi::grammar<std::string::const_iterator,
SpiceNetlist()> {
public:
using Iterator = std::string::const_iterator;
SpiceGrammar() : SpiceGrammar::base_type(spice_netlist) {
spice_netlist %=
element_statements >> *(element_statements);
element_statements %=
element_label >> element_node1 >> element_node2 >> element_value >>
qi::eol;
element_label %= (qi::char_ >> qi::char_) >> qi::space;
element_node1 %=
(qi::char_ >> qi::char_ >> qi::char_ >> qi::char_) >> qi::space;
element_node2 %=
qi::char_ >> qi::char_ >> qi::char_ >> qi::char_ >> qi::space;
element_value %= qi::double_;
BOOST_SPIRIT_DEBUG_NODE(spice_netlist);
BOOST_SPIRIT_DEBUG_NODE(element_statements);
BOOST_SPIRIT_DEBUG_NODE(element_label);
BOOST_SPIRIT_DEBUG_NODE(element_node1);
BOOST_SPIRIT_DEBUG_NODE(element_node2);
BOOST_SPIRIT_DEBUG_NODE(element_value);
}
qi::rule<Iterator, SpiceNetlist()> spice_netlist;
qi::rule<Iterator, ElementStatement> element_statements;
qi::rule<Iterator, boost::optional<std::string>()> element_label;
qi::rule<Iterator, boost::optional<std::string>()> element_node1;
qi::rule<Iterator, boost::optional<std::string>()> element_node2;
qi::rule<Iterator, boost::optional<double>()> element_value;
};
NetlistLoader::NetlistLoader() = default;
SpiceNetlist NetlistLoader::parse_netlist_from_string(
const std::string &netlist_string) const {
SpiceNetlist netlist;
std::cout << "Trying to parse:\n" << netlist_string << "\n";
std::cout << "Size of netlist_string: " << netlist_string.size() << std::endl;
auto iter = netlist_string.begin();
auto last = netlist_string.end();
std::cout << "Characters to go " << std::distance(iter, last) << std::endl;
bool success = qi::parse(iter, last, SpiceGrammar(), netlist);
std::cout << "Parsed: " << success << "\n";
std::cout << "Characters to go " << std::distance(iter, last) << std::endl
<< std::endl;
if (success) {
std::cout << "Parsed netlist content:" << std::endl;
for (std::size_t i = 0; i < netlist.element_statements.size(); ++i) {
const auto &statement = netlist.element_statements[i];
std::cout << "Element Label: ";
if (statement.element_label) {
std::cout << *statement.element_label;
} else {
std::cout << "Not specified";
}
std::cout << "\n ";
std::cout << "Element Node1: ";
if (statement.element_node1) {
std::cout << *statement.element_node1;
} else {
std::cout << "Not specified";
}
std::cout << "\n";
std::cout << "Element Node2: ";
if (statement.element_node2) {
std::cout << *statement.element_node2;
} else {
std::cout << "Not specified";
}
std::cout << "\n";
std::cout << "Element Value: ";
if (statement.element_value) {
std::cout << *statement.element_value;
} else {
std::cout << "Not specified";
}
std::cout << std::endl;
std::cout << std::endl;
}
} else {
std::cout << "Failed to parse netlist.\n";
}
return netlist;
}
I am able to sucessfully parse all the characters but I am only getting the first line i.e netlist.element_statement[0] as output.
Parsed netlist content
Element Label: V1
Element Node1: N001
Element Node2: N002
Element Value: 10
I have tried modifying the rule for element_statements to qi::rule<Iterator, std::vector()> element_statements; but it generates build errors.
Where am I going wrong?
You are dealing with whitespace manually, but never deal with new-line characters.
I suggest to leave the whitespace ignoring to a skipper, and specify the new-line separator (assuming it is required):
Using a
qi::blank
skipper you can simplify all the rules. I'd suggest replacing the blanketqi::char_
withqi::graph
which is probably what you intended.Also, don't bother with optional attributes, just make the expressions optional:
Demo
Live On Coliru
Printing
Summary/Notes
There were many simplifications in my listing.
There's one subtler point I want to point out: the rules marked "lexemes" do not use the declared skipper. This is important to avoid matching things across whitespace: Boost spirit skipper issues