123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- [/==============================================================================
- Copyright (C) 2001-2011 Joel de Guzman
- Copyright (C) 2001-2011 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 Karma subrules]
- [heading Description]
- The __karma__ `subrule` is a component allowing to create a named generator, 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 generator slightly faster (see
- [link spirit_repository.karma_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 generator 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/karma/calc2_ast_dump_sr.cpp]
- [calc2_ast_dump_sr_def]
- The example above can be found here: [@../../example/karma/calc2_ast_dump_sr.cpp]
- As shown in this code snippet (an extract from the calc2_ast_dump_sr example),
- subrules can be freely mixed with rules and grammars. Here, a group of
- 3 subrules (`ast_node`, `binary_node`, `unary_node`) is assigned to a rule (named
- `entry`). This means that parts of a generator 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/karma/nonterminal/subrule.hpp>
- #include <boost/spirit/repository/include/karma_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 delimiter type need not be specified
- in the parameters, unlike with grammars and rules.
- Subrules will automatically use the delimiter 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`] [Generator expressions. Can include `sr1` and `sr2`,
- as well as any other valid generator expressions.]]
- [[`srA`] [Subrule with a synthesized attribute and inherited
- attributes.]]
- [[`srB`] [Subrule with a synthesized attribute.]]
- [[`srC`] [Subrule with inherited attributes.]]
- [[`exprA`, `exprB`, `exprC`]
- [Generator 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 generator, which can be
- used anywhere in a generator expression (in assignments to rules, as well as
- directly in arguments to functions such as `generate`).
- In a group, generation 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<outiter_type> r1, r2, r3;
- subrule<1> sr1;
- subrule<2> sr2;
- r1 =
- ( sr1 = 'a' << space ) // 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' << space ) // 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 = space << 'x' ) // 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 subrule's synthesized attribute is automatically
- propagated to the RHS generator's 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/karma/mini_xml_karma_sr.cpp]
- Some includes:
- [mini_xml_karma_sr_includes]
- Some using declarations:
- [mini_xml_karma_sr_using]
- A grammar containing only one rule, defined with a group of 2 subrules:
- [mini_xml_karma_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/karma/mini_xml_karma_sr.cpp]
- [heading Performance]
- For comparison of run-time and compile-time performance when using subrules,
- please see the
- [link spirit_repository.qi_components.nonterminal.subrule.performance Performance]
- section of __qi__ subrules (the implementation of __karma__ and __qi__ subrules
- is very similar, so performance is very similar too).
- [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]
|