I would like to define a physical units parser using boost spirit. The parser will have to account for unit and also the prefix. To do this, I have too maps that stores the prefixes and the units in SI which are define below in pseudo-code.
std::map<std::string,double> prefixes;
// prefix - milli
prefixes["m"]=1.0e-03;
// prefix - centi
prefixes["c"]=1.0e-02;
...
std::map<std::string,std::vector<int>> units;
// time - seconds
units["s"] = {1,0,0,0,0,0,0};
// length - meters
units["m"] = {0,1,0,0,0,0,0};
...
These maps are not fixed (especially the later one) in the sense that the user may decide to define new prefixes and units.
I built the following grammar to parse strings such as kg or cm and to get as output a std::pair<double,std::vector<int>> that will contain the prefix and unit that match the successfully parsed string.
UnitParser.h
struct UnitParser : qi::grammar<std::string::const_iterator,std::pair<double,std::vector<int>>()>
{
UnitParser();
qi::rule<std::string::const_iterator,std::pair<double,std::vector<int>>()> prefixedUnitRule;
qi::rule<std::string::const_iterator,double()> prefixRule;
qi::rule<std::string::const_iterator,std::vector<int>()> unitRule;
};
and its cpp counterpart UnitParser.cpp:
UnitParser::UnitParser() : UnitParser::base_type(prefixedUnit)
{
using namespace qi;
using namespace phx;
prefixedUnitRule = prefixRule >> unitRule;
for (const auto& p : prefixes)
prefixRule = string(p.first)[_val=p.second] | prefixRule.copy()[_val=p.second];
for (const auto& p : units)
unitRule = string(p.first)[_val=p.second] | unitRule.copy()[_val=p.second];
}
This implementation compiles but produces wrong results.
My question/problem is the following, how to build the prefixRule and unitRule rules using a loop over the prefixes and units maps ?