Please note that I am asking about Boost.Parser, not the older Boost.Spirit.
I have a reference to a symbols
object that I want to use in a parsing rule. I think I want to use a parameter for that, but apparently the example of parameters in the tutorial is too complicated for me.
Here is the code I tried, which gives a compile error on the toprule_def
line.
#include <boost/parser/parser.hpp>
namespace bp = ::boost::parser;
bp::rule< struct toprule, double > toprule = "toprule";
auto const toprule_def = bp::double_ >> bp::_p<0>;
BOOST_PARSER_DEFINE_RULES( toprule );
static void ParamTest( const bp::symbols<double>& syms )
{
auto result = bp::parse( "10.3", toprule.with( syms ), bp::ws );
}
In comparison, if I wanted to do something like this in Spirit::Qi, I could create a grammar object with my symbol table reference as a member variable, and then use that symbol table in rules inside the grammar. Whereas Boost.Parser does not have grammars, and as far as I can tell, rules must be written in global scope.
You are not misunderstanding parameters, you're looking for lazy rule references.
Just like X3, Boost Parser doesn't currently seem to have support for that, whereas Qi did. I tackled this previously for X3 (Boost spirit x3 - lazy parser, see https://github.com/boostorg/spirit/issues/530).
However, Boost Parser doesn't advertise an x3::any_parser
equivalent, and I cannot quickly find an example of a custom parser directive either. The quickest thing I can think of is when you can tokenize the input independently, so you can defer the symbol lookup to a semantic action instead:
token [ lookup_sym(bp::_p<0>) ]
Here's a proof-of-concept:
#include <boost/parser/parser.hpp>
namespace bp = boost::parser;
using namespace bp::literals;
inline auto token = bp::lexeme[+(bp::char_ - bp::blank - bp::punct)];
auto lookup_sym = [](auto& ctx) {
auto const& syms = bp::_p<0>(ctx); // Get the symbols from the parser context
if (auto opt = syms.find(ctx, _attr(ctx))) {
_val(ctx) = *opt; // Assign the value associated with the token
} else
_pass(ctx) = false; // If not found, fail the parse
};
auto copy = [](auto& ctx) { _val(ctx) = _attr(ctx); };
bp::rule<struct toprule, double> toprule = "toprule";
static inline auto const toprule_def = bp::double_[copy] | token[lookup_sym];
BOOST_PARSER_DEFINE_RULES(toprule)
static void ParamTest(bp::symbols<double> const& syms) {
for (std::string const input : { "42e9", "-inf", "abc", "xyz" }) {
std::cout << "Parsed " << std::setw(6) << quoted(input);
if (auto result = bp::parse(input, toprule.with(std::cref(syms)), bp::ws))
std::cout << " -> value: " << result.value() << std::endl;
else
std::cerr << " FAILED" << std::endl;
}
}
int main() {
std::cout << " -------- " << std::endl;
ParamTest(bp::symbols<double> {{"abc", 10.3}});
std::cout << " -------- " << std::endl;
ParamTest(bp::symbols<double> {{"xyz", 10.3}});
}
Printing
--------
Parsed "42e9" -> value: 4.2e+10
Parsed "-inf" -> value: -inf
Parsed "abc" -> value: 10.3
Parsed "xyz" FAILED
--------
Parsed "42e9" -> value: 4.2e+10
Parsed "-inf" -> value: -inf
Parsed "abc" FAILED
Parsed "xyz" -> value: 10.3