| [/============================================================================== |
| 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 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] |