blob: 61331e467ef2d67ba61fc0aba11e79d62977337b [file] [log] [blame]
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2010 Hartmut Kaiser
Copyright (C) 2009 Francois Barel
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
===============================================================================/]
[section:subrule Qi subrules]
[heading Description]
The __qi__ `subrule` is a component allowing to create a named parser, and
to refer to it by name -- much like rules and grammars. It is in fact a fully
static version of the rule.
The strength of subrules is performance. Replacing some rules with subrules
can make a parser slightly faster (see
[link spirit_repository.qi_components.nonterminal.subrule.performance Performance]
below for measurements). The reason is that subrules allow aggressive inlining
by the C++ compiler, whereas the implementation of rules is based on a virtual
function call which, depending on the compiler, can have some run-time overhead
and stop inlining.
The weaknesses of subrules are:
* subrules can only be defined and used within the same parser expression. A
subrule cannot be defined at one location, and then used in another location.
* subrules put a massive strain on the C++ compiler. They increase compile
times and memory usage during compilation, and also increase the risk of
hitting compiler limits and/or bugs.
[import ../../example/qi/calc1_sr.cpp]
[calc1_sr_def]
The example above can be found here: [@../../example/qi/calc1_sr.cpp]
As shown in this code snippet (an extract from the calc1_sr example),
subrules can be freely mixed with rules and grammars. Here, a group of
3 subrules (`expression`, `term`, `factor`) is assigned to a rule (named
`entry`). This means that parts of a parser can use subrules (typically
the innermost, most performance-critical parts), whereas the rest can use
rules and grammars.
[heading Header]
// forwards to <boost/spirit/repository/home/qi/nonterminal/subrule.hpp>
#include <boost/spirit/repository/include/qi_subrule.hpp>
[heading Synopsis (declaration)]
subrule<ID, A1, A2> sr(name);
[heading Parameters (declaration)]
[table
[[Parameter] [Description]]
[[`ID`] [Required numeric argument. Gives the subrule
a unique 'identification tag'.]]
[[`A1`, `A2`] [Optional types, can be specified in any order.
Can be one of 1. signature, 2. locals
(see rules reference for more information on
those parameters).
Note that the skipper type need not be specified
in the parameters, unlike with grammars and rules.
Subrules will automatically use the skipper type
which is in effect when they are invoked.]]
[[`name`] [Optional string. Gives the subrule a name,
useful for debugging and error handling.]]
]
[heading Synopsis (usage)]
Subrules are defined and used within groups, typically (and by convention)
enclosed inside parentheses.
// Group containing N subrules
(
sr1 = expr1
, sr2 = expr2
, ... // Any number of subrules
}
The IDs of all subrules defined within the same group must be different. It is
an error to define several subrules with the same ID (or to define the same
subrule multiple times) in the same group.
// Auto-subrules and inherited attributes
(
srA %= exprA >> srB >> srC(c1, c2, ...) // Arguments to subrule srC
, srB %= exprB
, srC = exprC
, ...
)(a1, a2, ...) // Arguments to group, i.e. to start subrule srA
[heading Parameters (usage)]
[table
[[Parameter] [Description]]
[[`sr1`, `sr2`] [Subrules with different IDs.]]
[[`expr1`, `expr2`] [Parser expressions. Can include `sr1` and `sr2`,
as well as any other valid parser expressions.]]
[[`srA`] [Subrule with a synthesized attribute and inherited
attributes.]]
[[`srB`] [Subrule with a synthesized attribute.]]
[[`srC`] [Subrule with inherited attributes.]]
[[`exprA`, `exprB`, `exprC`]
[Parser expressions.]]
[[`a1`, `a2`] [Arguments passed to the subrule group. They are
passed as inherited attributes to the group's
start subrule, `srA`.]]
[[`c1`, `c2`] [Arguments passed as inherited attributes to
subrule `srC`.]]
]
[heading Groups]
A subrule group (a set of subrule definitions) is a parser, which can be
used anywhere in a parser expression (in assignments to rules, as well as
directly in arguments to functions such as `parse`).
In a group, parsing proceeds from the start subrule, which is the first
(topmost) subrule defined in that group. In the two groups in the synopsis
above, `sr1` and `srA` are the start subrules respectively -- for example
when the first subrule group is called forth, the `sr1` subrule is called.
A subrule can only be used in a group which defines it. Groups can be viewed
as scopes: a definition of a subrule is limited to its enclosing group.
rule<char const*> r1, r2, r3;
subrule<1> sr1;
subrule<2> sr2;
r1 =
( sr1 = 'a' >> int_ ) // First group in r1.
>> ( sr2 = +sr1 ) // Second group in r1.
// ^^^
// DOES NOT COMPILE: sr1 is not defined in this
// second group, it cannot be used here (its
// previous definition is out of scope).
;
r2 =
( sr1 = 'a' >> int_ ) // Only group in r2.
>> sr1
// ^^^
// DOES NOT COMPILE: not in a subrule group,
// sr1 cannot be used here (here too, its
// previous definition is out of scope).
;
r3 =
( sr1 = 'x' >> double_ ) // Another group. The same subrule `sr1`
// can have another, independent
// definition in this group.
;
[heading Attributes]
A subrule has the same behavior as a rule with respect to attributes. In
particular:
* the type of its synthesized attribute is the one specified in the
subrule's signature, if any. Otherwise it is `unused_type`.
* the types of its inherited attributes are the ones specified in the
subrule's signature, if any. Otherwise the subrule has no inherited
attributes.
* an auto-subrule can be defined by assigning it with the `%=` syntax.
In this case, the RHS parser's attribute is automatically propagated
to the subrule's synthesized attribute.
* the Phoenix placeholders `_val`, `_r1`, `_r2`, ... are available to
refer to the subrule's synthesized and inherited attributes, if present.
[heading Locals]
A subrule has the same behavior as a rule with respect to locals. In
particular, the Phoenix placeholders `_a`, `_b`, ... are available to
refer to the subrule's locals, if present.
[heading Example]
[import ../../example/qi/mini_xml2_sr.cpp]
Some includes:
[mini_xml2_sr_includes]
Some using declarations:
[mini_xml2_sr_using]
A grammar containing only one rule, defined with a group of 5 subrules:
[mini_xml2_sr_grammar]
The definitions of the `mini_xml` and `mini_xml_node` data structures
are not shown here. The full example above can be found here:
[@../../example/qi/mini_xml2_sr.cpp]
[heading Performance]
This table compares run-time and compile-time performance when converting
examples to subrules, with various compilers.
[table Subrules performance
[[Example] [Compiler]
[Speed (run-time)] [Time (compile-time)] [Memory (compile-time)]]
[[calc1_sr] [gcc 4.4.1] [ +6%] [ n/a] [ n/a]]
[[calc1_sr] [Visual C++ 2008 (VC9)] [ +5%] [ n/a] [ n/a]]
[[mini_xml2_sr] [gcc 3.4.6] [ -1%] [+54%] [+32%]]
[[mini_xml2_sr] [gcc 4.1.2] [ +5%] [+58%] [+25%]]
[[mini_xml2_sr] [gcc 4.4.1] [ +8%] [+20%] [+14%]]
[[mini_xml2_sr] [Visual C++ 2005 (VC8) SP1] [ +1%] [+33%] [+27%]]
[[mini_xml2_sr] [Visual C++ 2008 (VC9)] [ +9%] [+52%] [+40%]]
]
The columns are:
* *Speed (run-time)*: speed-up of the parser resulting from the use of
subrules (higher is better).
* *Time (compile-time)*: increase in compile time (lower is better).
* *Memory (compile-time)*: increase in compiler memory usage (lower is better).
[heading Notes]
Subrules push the C++ compiler hard. A group of subrules is a single C++
expression. Current C++ compilers cannot handle very complex expressions very
well. One restricting factor is the typical compiler's limit on template
recursion depth. Some, but not all, compilers allow this limit to be
configured.
g++'s maximum can be set using a compiler flag: `-ftemplate-depth`. Set this
appropriately if you use relatively complex subrules.
[endsect]