diff --git a/doc/intro.qbk b/doc/intro.qbk index a87e0f2a..7df84ab0 100644 --- a/doc/intro.qbk +++ b/doc/intro.qbk @@ -185,9 +185,6 @@ that have been retained in _Parser_. Both libraries: * use approximately the same set of directives to influence the parse (e.g. `lexeme[]`); -* provide loosely-coupled rules that are separately compilable (at least for - Spirit X3); and - * are built around a flexible parse context object that has state added to and removed from it during the parse (again, comparing to Spirit X3). diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index 4b3952ed..c1acaca2 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -558,13 +558,16 @@ parser `doubles_def` work together. The `_def` suffix is a naming convention that this macro relies on to work. The tag type allows the rule parser, `doubles`, to call one of these overloads when used as a parser. -[note In case you're curious about exactly what code is produced by the above -use of _RULES_, it's two overloads of a function called `parse_rule()`. The -overloads each take a `struct doubles` parameter (to distinguish them from the -other overloads of `parse_rule()` for other rules) and parse using -`doubles_def`. You will never need to call any overload of `parse_rule()` -yourself; it is used internally by the parser that implements _rs_, -`rule_parser`.] +_RULES_ expands to two overloads of a function called `parse_rule()`. In the +case above, the overloads each take a `struct doubles` parameter (to +distinguish them from the other overloads of `parse_rule()` for other rules) +and parse using `doubles_def`. You will never need to call any overload of +`parse_rule()` yourself; it is used internally by the parser that implements +_rs_, `rule_parser`. + +Here is the definition of the macro that is expanded for each rule: + +[define_rule_definition] Now that we have the `doubles` parser, we can use it like we might any other parser: @@ -2545,8 +2548,6 @@ common use cases for _rs_. Use a _r_ if you want to: * create a set of mutually-recursive parsers; -* separately compile a parser; or - * do callback parsing. Let's look at the use cases in detail. @@ -2856,40 +2857,6 @@ strings, etc. Since we need to be able to parse objects within arrays and vice versa, we need each of those two parsers to be able to refer to each other. -[heading Separately compiled rules] - -_Parser_ is obviously very template-heavy. However, the template parameters -used in your in _Parser_ code are all known at the time you write your rules -and parsers _emdash_ except for the range you're parsing. - -Therefore, if you know you're only going to parse with a single kind of range, -you can declare a function that does the parsing, and put the implementation -in a .cpp file. I know. A Boost author talking about putting code in -non-header files is weird. Let's see an example; first, we forward declare -our parse function in a header. - - // foo.h - bool balanced_parens(std::string_view str); - -Then we define the function, plus all the rules and parsers it uses, in an -implementation file: - - // foo.cpp - namespace { - namespace bp = boost::parser; - bp::rule parens = "matched parentheses"; - auto const parens_def = ('(' >> parens > ')') | bp::eps; - BOOST_PARSER_DEFINE_RULES(parens); - } - bool balanced_parens(std::string_view str) - { - namespace bp = boost::parser; - return bp::parse(str, bp::omit[parens], bp::ws); - } - -For large parsers, separate compilation can be a significant savings on build -time. - [heading Callback parsing] Only _rs_ can be callback parsers, so if you want to get attributes supplied @@ -4001,18 +3968,6 @@ Some things to note: The error will be "Expected '"', '\', '/', 'b', 'f', 'n', 'r', or 't' here", which is pretty helpful. -[heading Compile separately when you know the type of your input will not change] - -If your input type will not change (for instance, if you always parse from a -`std::string` and nothing else), you can use separate compilation to keep from -recompiling your parsing code over and over in every translation unit that -includes it. For instance, in the JSON callback parser example, there is a -call to `json::parse()`, which is a template. However, the function template -is always instantiated with the same parameter: `json_callbacks`, a type -defined in the example. It would be possible to remove the template parameter -from `json::parse()`, forward declare `json_callbacks` and `json::parse()`, -and define them in a different implementation file. - [heading Have a simple test that you can run to find ill-formed-code-as-asserts] Most of these errors are found at parser construction time, so no actual diff --git a/include/boost/parser/parser.hpp b/include/boost/parser/parser.hpp index 1a7c2869..59aba6d3 100644 --- a/include/boost/parser/parser.hpp +++ b/include/boost/parser/parser.hpp @@ -5310,7 +5310,8 @@ namespace boost { namespace parser { #ifndef BOOST_PARSER_DOXYGEN -#define BOOST_PARSER_DEFINE_IMPL(_, diagnostic_text_) \ +//[ define_rule_definition +#define BOOST_PARSER_DEFINE_IMPL(_, rule_name_) \ template< \ bool UseCallbacks, \ typename Iter, \ @@ -5318,7 +5319,7 @@ namespace boost { namespace parser { typename Context, \ typename SkipParser> \ auto parse_rule( \ - decltype(diagnostic_text_)::parser_type::tag_type *, \ + decltype(rule_name_)::parser_type::tag_type *, \ std::bool_constant use_cbs, \ Iter & first, \ Sentinel last, \ @@ -5327,7 +5328,7 @@ namespace boost { namespace parser { boost::parser::detail::flags flags, \ bool & success) \ { \ - auto const & parser = BOOST_PARSER_PP_CAT(diagnostic_text_, _def); \ + auto const & parser = BOOST_PARSER_PP_CAT(rule_name_, _def); \ return parser(use_cbs, first, last, context, skip, flags, success); \ } \ \ @@ -5339,7 +5340,7 @@ namespace boost { namespace parser { typename SkipParser, \ typename Attribute> \ void parse_rule( \ - decltype(diagnostic_text_)::parser_type::tag_type *, \ + decltype(rule_name_)::parser_type::tag_type *, \ std::bool_constant use_cbs, \ Iter & first, \ Sentinel last, \ @@ -5349,7 +5350,7 @@ namespace boost { namespace parser { bool & success, \ Attribute & retval) \ { \ - auto const & parser = BOOST_PARSER_PP_CAT(diagnostic_text_, _def); \ + auto const & parser = BOOST_PARSER_PP_CAT(rule_name_, _def); \ using attr_t = decltype(parser( \ use_cbs, first, last, context, skip, flags, success)); \ if constexpr (boost::parser::detail::is_nope_v) { \ @@ -5359,12 +5360,15 @@ namespace boost { namespace parser { use_cbs, first, last, context, skip, flags, success, retval); \ } \ } +//] #endif /** For each given token `t`, defines a pair of `parse_rule()` overloads, used internally within Boost.Parser. Each such pair implements the - parsing behavior rule `t`, using the parser `t_def`. */ + parsing behavior rule `t`, using the parser `t_def`. This + implementation is in the form of a pair of function templates. You + should therefore write this macro only at namespace scope. */ #define BOOST_PARSER_DEFINE_RULES(...) \ BOOST_PARSER_PP_FOR_EACH(BOOST_PARSER_DEFINE_IMPL, _, __VA_ARGS__)