early-access version 3088

This commit is contained in:
pineappleEA
2022-11-05 15:35:56 +01:00
parent 4e4fc25ce3
commit b601909c6d
35519 changed files with 5996896 additions and 860 deletions

View File

@@ -0,0 +1,33 @@
#==============================================================================
# Copyright (c) 2001-2011 Joel de Guzman
# Copyright (c) 2001-2011 Hartmut Kaiser
#
# Use, modification and distribution is subject to 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)
#==============================================================================
project spirit/repository/doc ;
import boostbook ;
import quickbook ;
path-constant images_location : html ;
boostbook spirit2_repository
:
spirit2_repository.qbk
:
<xsl:param>boost.root=../../../../..
<xsl:param>chunk.section.depth=4
<xsl:param>chunk.first.sections=1
<xsl:param>toc.section.depth=3
<xsl:param>toc.max.depth=3
<xsl:param>generate.section.toc.level=4
<format>html:<xsl:param>admon.graphics.path=images/
<include>.
<format>pdf:<xsl:param>img.src.path=$(images_location)/
<format>pdf:<xsl:param>draft.mode="no"
<format>pdf:<xsl:param>"boost.url.prefix=http://www.boost.org/doc/libs/release/libs/spirit/repository/doc/html"
;

View File

@@ -0,0 +1,34 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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 Acknowledgments]
The __spirit__ repository is the result of the contributions of active members
of the Spirit community. We would like to express our thanks to all who
directly contributed and to everybody directly or indirectly involved in the
discussions, which led to the creation of the parser and generator components.
The following people have directly contributed code to this repository:
[*Aaron Graham] wrote the __qi_advance__ parser component, which allows the
parser to skip (advance) through a specified number of iterations without
performing unnecessary work.
[*Chris Hoeppler] submitted the __qi_confix__ parser directive allowing to
embed a parser (the subject) inside an opening (the prefix) and a closing
sequence (the suffix).
[*Francois Barel] contributed the __qi_subrule__ parser and __karma_subrule__
generator components, allowing to create a named parser or generator, and
to refer to it by name. These components are in fact fully static versions of
the corresponding `rule` component.
[*Thomas Bernard] contributed the __qi_keywords__ and __qi_keywords_list__
parser components, allowing to define keyword parsers.
[endsect]

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,16 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<!-- Copyright (C) 2002 Douglas Gregor <doug.gregor -at- gmail.com>
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) -->
<title>Redirect to generated documentation</title>
<meta http-equiv="refresh" content="0; URL=http://boost-sandbox.sourceforge.net/libs/spirit/repository/doc/html/">
</head>
<body>
Automatic redirection failed, please go to
<a href="http://boost-sandbox.sourceforge.net/libs/spirit/repository/doc/html/">http://boost-sandbox.sourceforge.net/libs/spirit/repositorys/doc/html/</a>
</body>
</html>

View File

@@ -0,0 +1,16 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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 Karma Components]
[/include karma/primitive_generators.qbk]
[include karma/directives.qbk]
[include karma/nonterminals.qbk]
[/include karma/compound_generators.qbk]
[endsect]

View File

@@ -0,0 +1,10 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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:compound Karma Compound Generators]
[endsect]

View File

@@ -0,0 +1,151 @@
[/==============================================================================
Copyright (C) 2001-2011 Hartmut Kaiser
Copyright (C) 2001-2011 Joel de Guzman
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 Karma Confix Generator]
[heading Description]
The __karma__ `confix` generator is a generator directive component
allowing to embed any generated output inside an opening (a prefix) and a
closing (a suffix). A simple example is a C comment: `/* This is a C comment */`
which can be generated using the `confix` generator as:
`confix("/*", "*/")["This is a C comment"]`. The general syntax for using the
`confix` is:
confix(prefix, suffix)[subject]
which results in generating a sequence equivalent to
prefix << subject << suffix
Using the `confix` component instead of the explicit sequence has the advantage
of being able to encapsulate the prefix and the suffix into a separate generator
construct. The following code snippet illustrates the idea:
// Define a metafunction allowing to compute the type of the confix()
// construct
namespace traits
{
using namespace boost::spirit;
template <typename Prefix, typename Suffix = Prefix>
struct confix_spec
: spirit::result_of::terminal<repository::tag::confix(Prefix, Suffix)>
{};
};
// Define a helper function allowing to create a confix() construct from
// arbitrary prefix and suffix generators
template <typename Prefix, typename Suffix>
typename traits::confix_spec<Prefix, Suffix>::type
confix_spec(Prefix const& prefix, Suffix const& suffix)
{
using namespace boost::spirit;
return repository::confix(prefix, suffix);
}
// Define a helper function to construct a HTML tag from the tag name
inline typename traits::confix_spec<std::string>::type
tag (std::string const& tagname)
{
return confix_spec("<" + tagname + ">", "</" + tagname + ">");
}
// Define generators for different HTML tags the HTML tag
typedef traits::confix_spec<std::string>::type ol = tag("ol"); // <ol>...</ol>
typedef traits::confix_spec<std::string>::type li = tag("li"); // <li>...</li>
Now, for instance, the above definitions allow to generate the HTML 'ol' tag
using a simple: `ol["Some text"]` (which results in `<ol>Some text</ol>`).
[heading Header]
// forwards to <boost/spirit/repository/home/karma/directive/confix.hpp>
#include <boost/spirit/repository/include/karma_confix.hpp>
[heading Synopsis]
confix(prefix, suffix)[subject]
[heading Parameters]
[table
[[Parameter] [Description]]
[[`prefix`] [The generator construct to use to format the
opening (the prefix). The prefix is the part
generated /before/ any output as generated by
the `subject`.]]
[[`suffix`] [The generator construct to use to format the
ending (the suffix). The suffix is the part
generated /after/ any output as generated by
the `subject`.]]
[[`subject`] [The generator construct to use to format the
actual output in between the `prefix` and `suffix`
parts.]]
]
All three parameters can be arbitrary complex generators themselves.
[heading Attribute]
The `confix` component exposes the attribute type of its subject as its own
attribute type. If the `subject` does not expose any attribute (the type is
`unused_type`), then the `confix` does not expose any attribute either.
a: A --> confix(p, s)[a]: A
[note This notation is used all over the Spirit documentation and reads as:
Given, `a` is generator, and `A` is the type of the attribute of generator
`a`, then the type of the attribute exposed by `confix(p, s)[a]` will be
`A` as well.]
[heading Example]
The following example shows simple use cases of the `confix` generator. We will
illustrate its usage by generating different comment styles and a function
prototype (for the full example code see here:
[@../../example/karma/confix.cpp confix.cpp])
[import ../../example/karma/confix.cpp]
[heading Prerequisites]
In addition to the main header file needed to include the core components
implemented in __karma__ we add the header file needed for the new `confix`
generator.
[karma_confix_includes]
To make all the code below more readable we introduce the following namespaces.
[karma_confix_namespace]
[heading Generating Different Comment Styles]
We will show how to generate different comment styles. First we will generate
a C++ comment:
[karma_confix_cpp_comment]
This code snippet will obviouly generate `// This is a comment \n `. Similarly
generating a 'C'-style comment proves to be straightforward:
[karma_confix_c_comment]
which again will generate `/* This is a comment */ `.
[heading Generating a Function Prototype]
Generating a function prototype given a function name a vector or parameter
names is simple as well:
[karma_confix_function]
which generates the expected output: `func(par1,par2,par3)`.
[endsect]

View File

@@ -0,0 +1,11 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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:directives Karma Generator Directives]
[include confix.qbk]
[endsect]

View File

@@ -0,0 +1,11 @@
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2010 Hartmut Kaiser
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:nonterminal Karma Generator Non-terminals]
[include subrule.qbk]
[endsect]

View File

@@ -0,0 +1,10 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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:primitive Karma Generator Primitives]
[endsect]

View File

@@ -0,0 +1,221 @@
[/==============================================================================
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]

View File

@@ -0,0 +1,88 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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 Preface]
[heading The Spirit Repository]
The __spirit__ repository is a community effort collecting different reusable
components (primitives, directives, grammars, etc.) for __qi__ parsers and
__karma__ generators. All components in the repository have been peer reviewed
and/or discussed on the __spirit_list__. The aim is to broaden the scope of the
__spirit__ library while being able to maintain its high standards in terms of
code quality, flexibility, and maintainability. At the same time it encourages
people to contribute even small components as it lessens the hurdle of becoming
a __boost__ and __spirit__ author.
Maintainability of the code and author commitment over a longer period of time
are crucial for /Spirit's/ success (as it is for the whole __boost__ project).
That allows the repository to play an additional role in terms of being a
proving ground for interested authors. It is a lot easier to remove code from
the repository than from the /Spirit/ core library. So if an author can't
maintain his/her contribution anymore for any reason, we are able to remove
those parts from the repository more easily.
The repository is an excellent way of evolving things. The /Spirit/ core has
been developed for years, so we have a certain confidence of it being properly
designed and exposing a proven API. On the other hand, new ideas often need
some time to 'come to the point'. Changing API's is part of this business. At
the same time changing API's always mean user disruption, which we want to keep
to a minimum. Again, changing things in the repository is ought to be a lot
easier than in the core library.
The quality of contributions is another key to success. That includes not only
the code itself, but takes into consideration such things as documentation,
tests, examples. The authors activity on the mailing list is related as well,
it's an important point. Only well supported things will evolve over time into
usable, high quality components. The mandatory discussions and the review of
contributions on the __spirit_list__ ensure the targeted high quality
standards.
Based on the user feedback and general usability of things it is possible over
time to move repository components/grammars into the /Spirit/ core library.
[heading How to use this manual]
Some icons are used to mark certain topics indicative of their relevance.
These icons precede some text to indicate:
[table Icons
[[Icon] [Name] [Meaning]]
[[__note__] [Note] [Generally useful information (an aside that
doesn't fit in the flow of the text)]]
[[__tip__] [Tip] [Suggestion on how to do something
(especially something that not be obvious)]]
[[__important__] [Important] [Important note on something to take
particular notice of]]
[[__caution__] [Caution] [Take special care with this - it may
not be what you expect and may cause bad
results]]
[[__danger__] [Danger] [This is likely to cause serious
trouble if ignored]]
]
This documentation is automatically generated by Boost QuickBook documentation
tool. QuickBook can be found in the __boost_tools__.
[heading Support]
Please direct all questions to Spirit's mailing list. You can subscribe to the
__spirit_list__. The mailing list has a searchable archive. A search link to
this archive is provided in __spirit__'s home page. You may also read and post
messages to the mailing list through __spirit_general__ (thanks to __gmane__).
The news group mirrors the mailing list. Here is a link to the archives:
__mlist_archive__.
[endsect] [/ Preface]

View File

@@ -0,0 +1,18 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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 Qi Components]
[include qi/primitive_parsers.qbk]
[include qi/directives.qbk]
[include qi/nonterminals.qbk]
[include qi/operators.qbk]
[/include qi/compound_parsers.qbk]
[endsect] [/ Qi]

View File

@@ -0,0 +1,122 @@
[/==============================================================================
Copyright (C) 2001-2011 Hartmut Kaiser
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2011 Aaron Graham
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:advance Qi advance Parser]
[heading Description]
The __qi__ `advance` is a primitive parser component allowing the parser to
skip (advance) through a specified number of iterations without performing
unnecessary work:
advance(distance)
The most obvious existing alternative to this, the `repeat` directive, will
cause the parser to advance one iterator at a time while usually performing
operations at each step. In some cases that work is unnecessary, as in the case
where large binary objects are being parsed. Take, for example, the following
binary data:
[pre
00 00 00 01 77 fc b4 51 0a b3 b7 ... 1e 60 70 b6 00 00 01 00
]
If the first 4 bytes are a little-endian 32-bit integer describing the length
of the subsequent data, but the data itself is not relevant to parsing, then the
repeat directive would cause all of the subsequent 16 MB of data to be consumed
one byte at a time while generating page faults or other superfluous I/O. If the
value is large, as it is in this case, the parser becomes very slow.
little_dword[_a = _1] >> repeat(_a)[byte_] >> little_dword...
The `advance` parser component solves this problem by performing as little work
as possible to advance the parser's iterator, and will optimize for the case of
random-access iterators by advancing directly to the desired relative iterator
position.
little_dword[_a = _1] >> advance(_a) >> little_dword...
[heading Header]
// forwards to <boost/spirit/repository/home/qi/primitive/advance.hpp>
#include <boost/spirit/repository/include/qi_advance.hpp>
[heading Synopsis]
advance(distance)
[heading Parameters]
[table
[[Parameter] [Description]]
[['distance'] [The distance that the iterator shall be advanced]]
]
[heading Attribute]
The `advance` component exposes no attribute (the exposed attribute type is
`unused_type`):
advance --> unused
[heading Example]
The following example shows simple use cases of the `advance` component. We will
illustrate its usage by generating parsers for some binary data (for the full
example code see
[@../../example/qi/advance.cpp advance.cpp])
[import ../../example/qi/advance.cpp]
[heading Prerequisites]
In addition to the main header file needed to include the core components
implemented in __qi__ we add the header file needed for the new `advance`
component.
[qi_advance_includes]
In order to make the examples below more readable we introduce or use the
following namespaces.
[qi_advance_namespaces]
[heading Setting up the Grammar]
This is a very simple grammar that recognizes several fields of a binary stream
of data. There are two fields explicitly delimited by a field indicating the
number of bytes that are spanned. They are separated by a literal string.
[qi_advance_grammar]
Note that the second binary field may either contain the number of specified
bytes, or the word "qi". If the `advance` parser component fails to advance the
specified number of bytes before reaching the end of input, it will fail and
the parser will attempt to descend into alternatives.
[heading Parsing a Correctly-delimited String of Data]
The data below is correctly delimited and will thus result in a valid parse.
Note that both random-access and bidirectional iterators are used here.
[qi_advance_example1]
[heading Parsing the Alternative Representation]
The data below is not correctly delimited, but will correctly parse because the
alternative word "qi" is available.
[qi_advance_example2]
[heading Notes]
The `advance` parser component will fail unconditionally on negative values.
It will never attempt to advance the iterator in the reverse direction.
[endsect]

View File

@@ -0,0 +1,10 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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:compound Qi Compound Parsers]
[endsect]

View File

@@ -0,0 +1,137 @@
[/==============================================================================
Copyright (C) 2001-2011 Hartmut Kaiser
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2009 Chris Hoeppler
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:confix Qi Confix Parser Directive]
[heading Description]
The __qi__ `confix` directive is a unary parser component allowing to embed a
parser (the subject) inside an opening (the prefix) and a closing (the suffix):
confix(prefix, suffix)[subject]
This results in a parser that is equivalent to the sequence
omit[prefix] >> subject >> omit[suffix]
A simple example is a parser for non-nested comments which can now be written
as:
confix("/*", "*/")[*(char_ - "*/")] // C style comment
confix("//", eol)[*(char_ - eol)] // C++ style comment
Using the `confix` directive instead of the explicit sequence has the advantage
of being able to encapsulate the prefix and the suffix into a separate construct.
The following code snippet illustrates the idea:
namespace spirit = boost::spirit;
namespace repo = boost::spirit::repository;
// Define a metafunction allowing to compute the type
// of the confix() construct
template <typename Prefix, typename Suffix = Prefix>
struct confix_spec
{
typedef typename spirit::result_of::terminal<
repo::tag::confix(Prefix, Suffix)
>::type type;
};
confix_spec<std::string>::type const c_comment = repo::confix("/*", "*/");
confix_spec<std::string>::type const cpp_comment = repo::confix("//", "\n");
Now, the comment parsers can be written as
c_comment[*(char_ - "*/")] // C style comment
cpp_comment[*(char_ - eol)] // C++ style comment
[note While the `confix_p(prefix, subject, suffix)` parser in __classic__
was equivalent to the sequence `prefix >> *(subject - suffix) >> suffix,
the __qi__ `confix` directive will not perform this refactoring any more.
This simplifies the code and makes things more explicit.]
[heading Header]
// forwards to <boost/spirit/repository/home/qi/directive/confix.hpp>
#include <boost/spirit/repository/include/qi_confix.hpp>
[heading Synopsis]
confix(prefix, suffix)[subject]
[heading Parameters]
[table
[[Parameter] [Description]]
[[`prefix`] [The parser for the opening (the prefix).]]
[[`suffix`] [The parser for the ending (the suffix).]]
[[`subject`] [The parser for the input sequence between the
`prefix` and `suffix` parts.]]
]
All three parameters can be arbitrarily complex parsers themselves.
[heading Attribute]
The `confix` directive exposes the attribute type of its subject as its own
attribute type. If the `subject` does not expose any attribute (the type is
`unused_type`), then the `confix` does not expose any attribute either.
a: A, p: P, s: S: --> confix(p, s)[a]: A
[note This notation is used all over the Spirit documentation and reads as:
Given, `a`, `p`, and `s` are parsers, and `A`, `P`, and `S` are the types
of their attributes, then the type of the attribute exposed by
`confix(p, s)[a]` will be `A`.]
[heading Example]
The following example shows simple use cases of the `confix` directive. We will
illustrate its usage by generating parsers for different comment styles and
for some simple tagged data (for the full example code see
[@../../example/qi/confix.cpp confix.cpp])
[import ../../example/qi/confix.cpp]
[heading Prerequisites]
In addition to the main header file needed to include the core components
implemented in __qi__ we add the header file needed for the new `confix`
directive.
[qi_confix_includes]
In order to make the examples below more readable we import a number of
elements into the current namespace:
[qi_confix_using]
[heading Parsing Different Comment Styles]
We will show how to parse different comment styles. First we will parse
a C++ comment:
[qi_confix_cpp_comment]
This function will obviously parse input such as "`// This is a comment \n `".
Similarily parsing a 'C'-style comment proves to be straightforward:
[qi_confix_c_comment]
which again will be able to parse e.g. "`/* This is a comment */ `".
[heading Parsing Tagged Data]
Generating a parser that extracts the body from the HTML snippet "`<b>The Body</b>`"
is not very hard, either:
[qi_confix_tagged_data]
[endsect]

View File

@@ -0,0 +1,14 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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:directives Qi Parser Directives]
[include confix.qbk]
[include distinct.qbk]
[include kwd.qbk]
[include seek.qbk]
[endsect]

View File

@@ -0,0 +1,125 @@
[/==============================================================================
Copyright (C) 2001-2011 Hartmut Kaiser
Copyright (C) 2001-2011 Joel de Guzman
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:distinct Qi Distinct Parser Directive]
[heading Description]
The __qi__ `distinct` parser is a directive component allowing to avoid partial
matches while parsing using a skipper. A simple example is the common task of
matching a C keyword.
Consider:
"description" >> -lit(":") >> *(char_ - eol)
intended to match a line in a configuration file. Let's assume further, that
this rule is used with a `space` skipper and that we have the following strings
in the input:
"description: ident\n"
"description ident\n"
"descriptionident\n"
It might seem unexpected, but the parser above matches all three inputs just
fine, even if the third input should not match at all! In order to avoid the
unwanted match we are forced to make our rule more complicated:
lexeme["description" >> !char_("a-zA-Z_0-9")] >> -lit(":") >> *(char_ - eol)
(the rule reads as: match `"description"` as long as it's not /directly/
followed by a valid identifier).
The `distinct[]` directive is meant to simplify the rule above:
distinct(char_("a-zA-Z_0-9"))["description"] >> -lit(":") >> *(char_ - eol)
Using the `distinct[]` component instead of the explicit sequence has the
advantage of being able to encapsulate the tail (i.e the `char_("a-zA-Z_0-9")`)
as a separate parser construct. The following code snippet illustrates the idea
(for the full code of this example please see
[@../../test/qi/distinct.cpp distinct.cpp]):
[import ../../test/qi/distinct.cpp]
[qi_distinct_encapsulation]
These definitions define a new Qi parser recognizing keywords! This allows to
rewrite our declaration parser expression as:
keyword["description"] >> -lit(":") >> *(char_ - eol)
which is much more readable and concise if compared to the original parser
expression. In addition the new `keyword[]` directive has the advantage to be
usable for wrapping any parser expression, not only strings as in the example
above.
[heading Header]
// forwards to <boost/spirit/repository/home/qi/directive/distinct.hpp>
#include <boost/spirit/repository/include/qi_distinct.hpp>
[heading Synopsis]
distinct(tail)[subject]
[heading Parameters]
[table
[[Parameter] [Description]]
[[`tail`] [The parser construct specifying what whould not
follow the subject in order to match the overall
expression.]]
[[`subject`] [The parser construct to use to match the current
input. The distinct directive makes sure that no
unexpected partial matches occur.]]
]
All two parameters can be arbitrary complex parsers themselves.
[heading Attribute]
The `distinct` component exposes the attribute type of its subject as its own
attribute type. If the `subject` does not expose any attribute (the type is
`unused_type`), then the `distinct` does not expose any attribute either.
a: A, b: B --> distinct(b)[a]: A
[heading Example]
The following example shows simple use cases of the `distinct` parser.
[@../../example/qi/distinct.cpp distinct.cpp])
[import ../../example/qi/distinct.cpp]
[heading Prerequisites]
In addition to the main header file needed to include the core components
implemented in __qi__ we add the header file needed for the new `distinct`
generator.
[qi_distinct_includes]
To make all the code below more readable we introduce the following namespaces.
[qi_distinct_namespace]
[heading Using The Distinct Directive to Match keywords]
We show several examples of how the `distinct[]` directive can be used to force
correct behavior while matching keywords. The first two code snippets show
the correct matching of the `description` keyword (in this hypothetical example
we allow keywords to be directly followed by an optional `"--"`):
[qi_distinct_description_ident]
[qi_distinct_description__ident]
The last example shows that the `distinct[]` parser component correctly refuses
to match "description-ident":
[qi_distinct_description_ident_error]
[endsect]

View File

@@ -0,0 +1,84 @@
[/==============================================================================
Copyright (C) 2001-2011 Hartmut Kaiser
Copyright (C) 2001-2011 Joel de Guzman
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:flush_multi_pass Qi flush_multi_pass parser]
[heading Description]
The __qi__ `flush_multi_pass` parser is a primitive (pseudo) parser component
allowing to clear the internal buffer of a `multi_pass` iterator. Clearing the
buffer of a `multi_pass` might be beneficial for grammars where it is clear
that no backtracking can occur.
The general syntax for using the `flush_multi_pass` is:
flush_multi_pass
which will call the `clear_queue()` member function if the current iterators
are of the type `multi_pass`. This will cause any buffered data to be erased.
This also will invalidate all other copies of multi_pass and they should not
be used. If they are, an `boost::illegal_backtracking` exception will be
thrown. For all other iterator types this is a no-op. The `flush_multi_pass`
generates a parser component which always succeeds and which does not consume
any input (very much like `eps`).
[heading Header]
// forwards to <boost/spirit/repository/home/qi/primitive/flush_multi_pass.hpp>
#include <boost/spirit/repository/include/qi_flush_multi_pass.hpp>
[heading Synopsis]
flush_multi_pass
[heading Parameters]
The `flush_multi_pass` does not require any parameters.
[heading Attribute]
The `flush_multi_pass` component exposes no attribute (the exposed attribute
type is `unused_type`):
flush_multi_pass --> unused
[heading Example]
The following example shows a simple use case of the `flush_multi_pass` parser.
We will illustrate its usage by generating different comment styles and a
function prototype (for the full example code see here:
[@../../example/qi/flush_multi_pass.cpp flush_multi_pass.cpp])
[import ../../example/qi/flush_multi_pass.cpp]
[heading Prerequisites]
In addition to the main header file needed to include the core components
implemented in __qi__ we add the header file needed for the new
`flush_multi_pass` parser.
[qi_flush_multi_pass_includes]
To make all the code below more readable we introduce the following namespaces.
[qi_flush_multi_pass_namespace]
[heading Clearing the internal buffer]
The example grammar recognizes the (simplified) preprocessor commands `#define`
and `#undef` both of which are constraint to a single line. This makes it
possible to delete all internal iterator buffers on each detected line break.
This is safe as no backtracking will occur after any line end. The following
code snippet shows the usage of `flush_multi_pass` for this purpose.
[qi_flush_multi_pass_clear_buffer]
[note Using the `flush_multi_pass` parser component with iterators other than
`multi_pass` is safe as it has no effect on the parsing.]
[endsect]

View File

@@ -0,0 +1,103 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
Copyright (C) 2011 Thomas Bernard
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:keyword_list Keyword List Operator]
[heading Description]
The keyword list operator, `kwd("k1")[a] / kwd("k2")[b]`, works tightly with the kwd, ikwd, dkwd and idkwd directives
to efficiently match keyword lists. As long as one of the keywords specified through the kwd, ikwd, dkwd or idkwd directive
matches, the keyword will be immediately followed by the keyword's associated subject parser.
The parser will continue parsing input as long as the one of the keywords and it's associated parser succeed.
Writing :
(kwd("k1")[a] / kwd("k2")[b] / ... )
is equivalent to:
*( "k1" > a | "k2" > b ... ).
[heading Header]
// forwards to <boost/spirit/repository/home/qi/operator/keywords.hpp>
#include <boost/spirit/repository/include/qi_keywords.hpp>
[heading Expression Semantics]
[table
[[Expression] [Semantics]]
[[`kwd(k1)[a] / kwd(k2)[b]`] [Match `lit(k1) > a` or `lit(k2) > b`, equivalent to `lit(k1) > a | lit(k2) > b`]]
]
[heading Attributes]
[table
[[Expression] [Attribute]]
[[`kwd("k1")[a] / kwd("k2")[b]`]
[``a: A, b: B --> (kwd(k1)[a] / kwd(k2)[b]): tuple<A, B>
a: A, b: Unused --> (kwd(k1)[a] / kwd(k2)[b]): optional<A>
a: Unused, b: B --> (kwd("k1")[a] / kwd(k2)[b]): optional<B>
a: Unused, b: Unused --> (kwd(k1)[a] / kwd(k2)[b]): Unused
a: A, b: A -->(kwd(k1)[a] / kwd(k2)[b]): tuple<A, A>``]]
]
[note The keyword list parser works tightly with the kwd, ikwd, dkwd and idkwd directives
and can't be used without it. A compile time error will warn you
of any mistakes. This parser collects all the kwd directives and
extracts the keyword literals or parsers from the directives to internaly
build a Ternary Search Tree (TST) and permutation loop (for complex parsers)
to effectively parse the keywords.
Because you can't mix character types inside a TST you must take
care not to mix wide strings with normal strings in the keywords you supply
to a keyword list. Should it happen the compiler will trap the mistake for you.]
[note The kwd directive also works a bit like the repeat directive
and can be used to formulate additional contraints on the number of
times a keyword can or must occur while parsing a keyword list.]
[note The kwd, dkwd and ikwd, idkwd directives can be mixed inside a keyword list. This has
however a small overhead and should be avoided when possible.]
[heading Complexity]
[:The overall complexity of the keyword list parser is defined by the
sum of the complexities of its elements.]
[heading Example]
[import ../../example/qi/keywords.cpp]
[note The test harness for the example(s) below is presented in the
__qi_basics_examples__ section.]
Declare a small data structure representing a person:
[reference_keyword_list_test_data_structure]
Some using declarations:
[reference_using_declarations_keyword_list]
Now let's declare a keyword parser:
[reference_keyword_list_no_constraint_rule]
A couple of input string variations run on the same parser:
[reference_keyword_list]
Now let's delcare a parser with some occurrence constraints:
[reference_keyword_list_constraint_rule]
And see how it works in these two cases:
[reference_keyword_list_constraints]
[endsect] [/ Keyword list]

View File

@@ -0,0 +1,110 @@
[/==============================================================================
Copyright (C) 2001-2012 Joel de Guzman
Copyright (C) 2001-2012 Hartmut Kaiser
Copyright (C) 2011-2012 Thomas Bernard
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:kwd Qi Keyword Parser Directive ]
[heading Description]
The `kwd[]`, `dkwd[]` and `ikwd[]`, `idkwd[]` provide a powerful and flexible mechanism for parsing keyword
based input. It works in conjunction with the / operator to create an effective
keyword parsing loop. The keyword parsing loop doesn't require the
keywords to appear in a defined order in the input but also provides the possibility
to check how many times a keyword appears in the input.
The kwd directive will parse the keywords respecting case sensitivity whereas the ikwd
direcive is case insensitive. You can mix the kwd and ikwd directives inside a set of
keywords, but be aware that this has a small overhead. It should be preferred not to
mix the kwd and ikwd directives.
The dkwd and idkwd provide a mechanism to pase distinct keywords. These directives require
that the skipper successeds parsing input right after the keyword part.
dkwd("keyword1")['='>>int_]
is equivalent to:
lit("keyword1") >> skipper+ >> '=' >> int_
All the keyword directives can be mixed inside a keyword list.
The kwd directive is very similar to the repeat directive in that it enables to enforce
keyword occurrence constraints but also provides very interesting speed improvement
over the pure EBNF syntax or the Nabialek-Trick.
[heading Header]
// forwards to <boost/spirit/repository/home/qi/directive/kwd.hpp>
#include <boost/spirit/repository/include/qi_kwd.hpp>
[heading Synopsis]
[table
[[Expression] [Semantics]]
[[`kwd(keyword)[subject]`] [Parse ( `"keyword"` > `subject`) zero or more times.]]
[[`kwd(keyword,n)[subject]`] [Parse ( `"keyword"` > `subject`) exactly `n` times.]]
[[`kwd(keyword,min, max)[subject]`] [Parse ( `"keyword"` > `subject`) at least `min` times and at most `max` times.]]
[[`kwd(keyword,min, inf)[subject]`] [Parse ( `"keyword"` > `subject`) at least `min` or more. ]]
]
For non case sensitive keywords use the ikwd directive.
If distinct keyword parsing is required, use the dkwd and idkwd directive instead.
[heading Parameters]
[table
[[Parameter] [Description]]
[[`keyword`] [The parser for the opening (the prefix).]]
[[`subject`] [The parser for the input sequence following the keyword part.]]
[[`n`] [Int representing the exact number of times the keyword must be repeated.]]
[[`min`] [Int representing the minimum number of times the keyword must be repeated.]]
[[`max`] [Int representing the maximum number of times the keyword must be repeated.]]
]
The keyword as well as the subject parameters can be any valid spirit parser.
The parameter n, min and max are integer constants.
[heading Attributes]
[table
[[Expression] [Attribute]]
[[`kwd(k1)[a]`]
[``a: A --> kwd(k1)[a]: optional<A> or vector<A>
a: Unused --> kwd(k1)[a]: Unused``]]
[[`kwd(k1,n)[a]`]
[``a: A --> kwd(k1,n)[a]: optional<A> or vector<A>
a: Unused --> kwd(k1,n)[a]: Unused``]]
[[`kwd(k1,min, max)[a]`]
[``a: A --> kwd(k1,min, max)[a]: optional<A> or vector<A>
a: Unused --> kwd(k1,min, max)[a]: Unused``]]
[[`kwd(k1,min, inf)[a]`]
[``a: A --> kwd(k1,min, inf)[a]: optional<A> or vector<A>
a: Unused --> kwd(k1,min, inf)[a]: Unused``]]
]
[heading Complexity]
[:The overall complexity is defined by the complexity of its subject
parser. The complexity of the keyword list construct `kwd` itself is O(N), where N is the number
of repetitions executed.
In the case where all the keywords are strings, the complexity of the keyword list itself determined by the complexity of the internal TST contents :
O(log n+k)
Where k is the length of the string to be searched in a TST with n strings.
When the keywords used are complex parsers, then the complexity is the sum of the sub parser complexities.
]
[heading Example]
Please refer to keyword_list.
[endsect]

View File

@@ -0,0 +1,11 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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:nonterminal Qi Parser Non-terminals]
[include subrule.qbk]
[endsect]

View File

@@ -0,0 +1,11 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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:operators Qi Parser Operators]
[include keywords.qbk]
[endsect]

View File

@@ -0,0 +1,12 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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:primitive Qi Parser Primitives]
[include advance.qbk]
[include flush_multi_pass.qbk]
[endsect]

View File

@@ -0,0 +1,93 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
Copyright (C) 2011 Jamboree
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:seek Qi Seek Parser Directive ]
[heading Description]
The `seek[]` parser-directive skips all input until the subject parser matches.
[heading Header]
// forwards to <boost/spirit/repository/home/qi/directive/seek.hpp>
#include <boost/spirit/repository/include/qi_seek.hpp>
Also, see __include_structure__.
[heading Namespace]
[table
[[Name]]
[[`boost::spirit::repository::qi::seek`]]
]
[heading Model of]
[:__unary_parser_concept__]
[variablelist Notation
[[`a`] [A __parser_concept__.]]
]
[heading Expression Semantics]
Semantics of an expression is defined only where it differs from, or is
not defined in __unary_parser_concept__.
[table
[[Expression] [Semantics]]
[[`seek[a]`] [Advances until the parser `a` matches.]]
]
[heading Attributes]
See __qi_comp_attr_notation__.
[table
[[Expression] [Attribute]]
[[`seek[a]`]
[``a: A --> seek[a]: A
a: Unused --> seek[a]: Unused``]]
]
[heading Complexity]
[:The overall complexity is defined by the complexity of its subject
parser. The complexity of `seek` itself is O(N), where N is the number
of unsuccessful matches.]
[note *seeking sequence with skipping*
Using `seek[a >> b]` with skipping is inefficient, because when sequence fails, the backtracked position is non-skipped.
The solution is to ensure the input will always be pre-skipped, for example:
``
seek[lexeme[skip[a >> b]]]
``
does the trick.]
[heading Example]
[import ../../example/qi/seek.cpp]
The following example shows a simple use case of the `seek[]` directive, parsing C-style comment.
(For the full source of the example, see [@../../example/qi/seek.cpp seek.cpp])
Some namespace aliases:
[reference_qi_seek_namespace]
The input string and its iterators:
[reference_qi_seek_vars]
Parsing and showing the result:
[reference_qi_seek_parse]
[endsect]

View File

@@ -0,0 +1,240 @@
[/==============================================================================
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 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]

View File

@@ -0,0 +1,38 @@
[/==============================================================================
Copyright (C) <year> <name>
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 <name of component>]
[heading Description]
[/ describe the component here]
[heading Header]
#include <boost/spirit/repository/include/...>
[heading Synopsis]
[/ short usage synopsis]
[heading Parameters]
[table
[[Parameter] [Description]]
[[parameter in synopsis] [describe parameter]]
]
[heading Attribute]
[/ describe the rules for attribute construction and propagation of your
component, use the same notation as used in the main Spirit docs]
[heading Example]
[/ describe some examples here, use uiqckbooks import feature to show the code]
[endsect]

View File

@@ -0,0 +1,114 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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)
===============================================================================/]
[article Spirit Repository
[quickbook 1.4]
[version 0.2]
[authors [de Guzman, Joel], [Kaiser, Hartmut]]
[copyright 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 Joel de Guzman, Hartmut Kaiser]
[/ purpose Parser and Generator Library]
[license
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])
]
]
[/ May 26, 2009 ]
[def __spirit__ [@http://boost-spirit.com Spirit]]
[def __spirit_list__ [@http://boost.2283326.n4.nabble.com/spirit-general-f2672582.html Spirit General List]]
[def __phoenix__ [@boost:/libs/phoenix/doc/html/index.html Boost.Phoenix]]
[def __fusion__ [@http://spirit.sourceforge.net/dl_more/fusion_v2/libs/fusion/doc/html/index.html Fusion]]
[def __mpl__ [@http://www.boost.org/libs/mpl/index.html MPL]]
[def __boost__ [@http://www.boost.org/ Boost]]
[def __boost_tools__ [@http://www.boost.org/tools/index.html Boost Tools]]
[def __spirit_list__ [@https://lists.sourceforge.net/lists/listinfo/spirit-general Spirit Mailing List]]
[def __spirit_general__ [@news://news.gmane.org/gmane.comp.spirit.general Spirit General NNTP news portal]]
[def __gmane__ [@http://www.gmane.org Gmane]]
[def __mlist_archive__ [@http://news.gmane.org/gmane.comp.parsers.spirit.general]]
[def __classic__ /Spirit.Classic/]
[def __qi__ /Spirit.Qi/]
[def __karma__ /Spirit.Karma/]
[def __lex__ /Spirit.Lex/]
[def __qi_advance__ [link spirit_repository.qi_components.primitive.advance `advance`]]
[def __qi_subrule__ [link spirit_repository.qi_components.nonterminal.subrule `subrule`]]
[def __qi_confix__ [link spirit_repository.qi_components.directives.confix `confix`]]
[def __qi_keywords__ [link spirit_repository.qi_components.operators.keyword_list keyword_list]]
[def __qi_keywords_list__ [link spirit_repository.qi_components.directives.kwd `kwd()[]`]]
[def __qi_seek__ [link spirit_repository.qi_components.directives.seek `seek[]`]]
[def __karma_subrule__ [link spirit_repository.karma_components.nonterminal.subrule `subrule`]]
[/ Some images ]
[def __note__ [$images/note.png]]
[def __tip__ [$images/tip.png]]
[def __important__ [$images/important.png]]
[def __caution__ [$images/caution.png]]
[def __danger__ [$images/alert.png]]
[/ ----------------------------------------------------------------------------]
[/ $$$ Refer to spirit2.qbk $$$]
[/ References to abstracts ]
[def __include_structure__ [@../../../doc/html/spirit/structure/include.html Include Structure]]
[/ quick-ref]
[def __qi_comp_attr_notation__ [@../../../doc/html/spirit/qi/quick_reference/compound_attribute_rules.html#spirit.qi.quick_reference.compound_attribute_rules.notation Compound Attribute Notation]]
[/ concepts]
[def __parser_concept__ [@../../../doc/html/spirit/qi/reference/parser_concepts/parser.html `Parser`]]
[def __primitive_parser_concept__ [@../../../doc/html/spirit/qi/reference/parser_concepts/primitiveparser.html `PrimitiveParser`]]
[def __unary_parser_concept__ [@../../../doc/html/spirit/qi/reference/parser_concepts/unaryparser.html `UnaryParser`]]
[def __binary_parser_concept__ [@../../../doc/html/spirit/qi/reference/parser_concepts/binaryparser.html `BinaryParser`]]
[def __nary_parser_concept__ [@../../../doc/html/spirit/qi/reference/parser_concepts/naryparser.html `NaryParser`]]
[def __qi_nonterminal__ [@../../../doc/html/spirit/qi/reference/parser_concepts/nonterminal.html `Nonterminal`]]
[def __qi_nonterminal_attribute__ [@../../../doc/html/spirit/qi/reference/parser_concepts/nonterminal.html#spirit.qi.reference.parser_concepts.nonterminal.attributes `Attribute`]]
[/ basics]
[def __qi_lazy_argument__ [@../../../doc/html/spirit/qi/reference/basics.html#spirit.qi.reference.basics.lazy_argument Lazy Argument]]
[def __qi_lazy_arguments__ [@../../../doc/html/spirit/qi/reference/basics.html#spirit.qi.reference.basics.lazy_argument Lazy Arguments]]
[def __char_encoding_namespace__ [@../../../doc/html/spirit/qi/reference/basics.html#spirit.qi.reference.basics.character_encoding_namespace Character Encoding Namespace]]
[def __string__ [@../../../doc/html/spirit/qi/reference/basics.html#spirit.qi.reference.basics.string String]]
[def __qi_basics_examples__ [@../../../doc/html/spirit/qi/reference/basics.html#spirit.qi.reference.basics.examples Basics Examples]]
[/ quick-ref]
[def __karma_comp_attr_notation__ [@../../../doc/html/spirit/karma/quick_reference/compound_attribute_rules.html#spirit.karma.quick_reference.compound_attribute_rules.notation Compound Attribute Notation]]
[/ concepts]
[def __generator_concept__ [@../../../doc/html/spirit/karma/reference/generator_concepts/generator.html `Generator`]]
[def __primitive_generator_concept__ [@../../../doc/html/spirit/karma/reference/generator_concepts/primitivegenerator.html `PrimitiveGenerator`]]
[def __unary_generator_concept__ [@../../../doc/html/spirit/karma/reference/generator_concepts/unarygenerator.html `UnaryGenerator`]]
[def __binary_generator_concept__ [@../../../doc/html/spirit/karma/reference/generator_concepts/binarygenerator.html `BinaryGenerator`]]
[def __nary_generator_concept__ [@../../../doc/html/spirit/karma/reference/generator_concepts/narygenerator.html `NaryGenerator`]]
[def __karma_nonterminal_concept__ [@../../../doc/html/spirit/karma/reference/generator_concepts/nonterminal.html `Nonterminal`]]
[def __karma_nonterminal_attribute__ [@../../../doc/html/spirit/karma/reference/generator_concepts/nonterminal.html#spirit.karma.reference.generator_concepts.nonterminal.attributes `Attribute`]]
[/ basics]
[def __karma_lazy_argument__ [@../../../doc/html/spirit/karma/reference/basics.html#spirit.karma.reference.basics.lazy_argument Lazy Argument]]
[def __karma_lazy_arguments__ [@../../../doc/html/spirit/karma/reference/basics.html#spirit.karma.reference.basics.lazy_argument Lazy Arguments]]
[def __karma_basics_examples__ [@../../../doc/html/spirit/karma/reference/basics.html#spirit.karma.reference.basics.examples Basics Examples]]
[/ ----------------------------------------------------------------------------]
[/ Here we go ]
[include preface.qbk]
[include what_s_new.qbk]
[include qi.qbk]
[include karma.qbk]
[include acknowledgements.qbk]

View File

@@ -0,0 +1,23 @@
[/==============================================================================
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2001-2011 Hartmut Kaiser
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 What's New]
[/////////////////////////////////////////////////////////////////////////////]
[section:spirit_2_5_1 Spirit V2.5.1]
This section is added since V2.5.1 (Boost V1.48.0).
[heading New Features in Qi]
* Added the __qi__ directive __qi_seek__ enabling skipping over the input,
getting to the interested portion.
[endsect]
[endsect]

View File

@@ -0,0 +1,16 @@
#==============================================================================
# Copyright (c) 2009 Chris Hoeppler
#
# 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)
#==============================================================================
project spirit_v2_repository/example_karma
: requirements
<c++-template-depth>300
;
exe karma_confix : confix.cpp ;
exe calc2_ast_dump_sr : calc2_ast_dump_sr.cpp ;
exe mini_xml_karma_sr : mini_xml_karma_sr.cpp ;

View File

@@ -0,0 +1,179 @@
/*=============================================================================
Copyright (c) 2001-2010 Joel de Guzman
Copyright (c) 2001-2012 Hartmut Kaiser
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)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// A Calculator example demonstrating generation of AST which gets dumped into
// a human readable format afterwards.
//
// [ JDG April 28, 2008 ]
// [ HK April 28, 2008 ]
//
///////////////////////////////////////////////////////////////////////////////
#if !defined(SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM)
#define SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM
#include <boost/variant.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/function.hpp>
#include <boost/phoenix/statement.hpp>
#include <boost/spirit/home/karma/domain.hpp>
#include <boost/spirit/include/support_attributes_fwd.hpp>
///////////////////////////////////////////////////////////////////////////////
// Our AST
///////////////////////////////////////////////////////////////////////////////
struct binary_op;
struct unary_op;
struct nil {};
struct expression_ast
{
typedef
boost::variant<
nil // can't happen!
, int
, boost::recursive_wrapper<binary_op>
, boost::recursive_wrapper<unary_op>
>
type;
// expose variant types
typedef type::types types;
// expose variant functionality
int which() const { return expr.which(); }
// constructors
expression_ast()
: expr(nil()) {}
expression_ast(unary_op const& expr)
: expr(expr) {}
expression_ast(binary_op const& expr)
: expr(expr) {}
expression_ast(unsigned int expr)
: expr(expr) {}
expression_ast(type const& expr)
: expr(expr) {}
expression_ast& operator+=(expression_ast const& rhs);
expression_ast& operator-=(expression_ast const& rhs);
expression_ast& operator*=(expression_ast const& rhs);
expression_ast& operator/=(expression_ast const& rhs);
type expr;
};
// expose variant functionality
namespace boost
{
// this function has to live in namespace boost for ADL to correctly find it
template <typename T>
inline T get(expression_ast const& expr)
{
return boost::get<T>(expr.expr);
}
// the specialization below tells Spirit to handle expression_ast as if it
// where a 'real' variant
namespace spirit { namespace traits
{
// the specialization below tells Spirit to handle expression_ast as
// if it where a 'real' variant (if used with Spirit.Karma)
template <>
struct not_is_variant<expression_ast, karma::domain>
: mpl::false_ {};
// the specialization of variant_which allows to generically extract
// the current type stored in the given variant like type
template <>
struct variant_which<expression_ast>
{
static int call(expression_ast const& v)
{
return v.which();
}
};
}}
}
///////////////////////////////////////////////////////////////////////////////
struct binary_op
{
binary_op() {}
binary_op(
char op
, expression_ast const& left
, expression_ast const& right)
: op(op), left(left), right(right) {}
char op;
expression_ast left;
expression_ast right;
};
struct unary_op
{
unary_op(
char op
, expression_ast const& right)
: op(op), right(right) {}
char op;
expression_ast right;
};
inline expression_ast& expression_ast::operator+=(expression_ast const& rhs)
{
expr = binary_op('+', expr, rhs);
return *this;
}
inline expression_ast& expression_ast::operator-=(expression_ast const& rhs)
{
expr = binary_op('-', expr, rhs);
return *this;
}
inline expression_ast& expression_ast::operator*=(expression_ast const& rhs)
{
expr = binary_op('*', expr, rhs);
return *this;
}
inline expression_ast& expression_ast::operator/=(expression_ast const& rhs)
{
expr = binary_op('/', expr, rhs);
return *this;
}
// We should be using expression_ast::operator-. There's a bug
// in phoenix type deduction mechanism that prevents us from
// doing so. Phoenix will be switching to BOOST_TYPEOF. In the
// meantime, we will use a phoenix::function below:
template <char Op>
struct unary_expr
{
template <typename T>
struct result { typedef T type; };
expression_ast operator()(expression_ast const& expr) const
{
return unary_op(Op, expr);
}
};
boost::phoenix::function<unary_expr<'+'> > pos;
boost::phoenix::function<unary_expr<'-'> > neg;
#endif

View File

@@ -0,0 +1,180 @@
/*=============================================================================
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)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// A Calculator example demonstrating generation of AST which gets dumped into
// a human readable format afterwards.
//
// [ JDG April 28, 2008 ]
// [ HK April 28, 2008 ]
//
///////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <vector>
#include <string>
#include "calc2_ast.hpp"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/repository/include/karma_subrule.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
using namespace boost::spirit;
using namespace boost::spirit::ascii;
namespace repo = boost::spirit::repository;
///////////////////////////////////////////////////////////////////////////////
// Our calculator parser grammar
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct calculator
: qi::grammar<Iterator, expression_ast(), space_type>
{
calculator() : calculator::base_type(expression)
{
expression =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1])
)
;
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1])
)
;
factor =
uint_ [_val = _1]
| '(' >> expression [_val = _1] >> ')'
| ('-' >> factor [_val = neg(_1)])
| ('+' >> factor [_val = pos(_1)])
;
}
qi::rule<Iterator, expression_ast(), space_type> expression, term, factor;
};
// We need to tell fusion about our binary_op and unary_op structs
// to make them a first-class fusion citizen
//
// Note: we register the members exactly in the same sequence as we need them
// in the grammar
BOOST_FUSION_ADAPT_STRUCT(
binary_op,
(expression_ast, left)
(char, op)
(expression_ast, right)
)
BOOST_FUSION_ADAPT_STRUCT(
unary_op,
(char, op)
(expression_ast, right)
)
///////////////////////////////////////////////////////////////////////////////
// Our AST grammar for the generator, this just dumps the AST as a expression
///////////////////////////////////////////////////////////////////////////////
template <typename OuputIterator>
struct dump_ast
: karma::grammar<OuputIterator, expression_ast(), space_type>
{
dump_ast() : dump_ast::base_type(entry)
{
//[calc2_ast_dump_sr_def
entry %= (
ast_node %= int_ | binary_node | unary_node
, binary_node %= '(' << ast_node << char_ << ast_node << ')'
, unary_node %= '(' << char_ << ast_node << ')'
);
//]
}
karma::rule<OuputIterator, expression_ast(), space_type> entry;
repo::karma::subrule<0, expression_ast()> ast_node;
repo::karma::subrule<1, binary_op()> binary_node;
repo::karma::subrule<2, unary_op()> unary_node;
};
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int
main()
{
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "Dump AST's for simple expressions...\n\n";
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "Type an expression...or [q or Q] to quit\n\n";
// Our parser grammar definitions
typedef std::string::const_iterator iterator_type;
typedef calculator<iterator_type> calculator;
calculator calc;
// Our generator grammar definitions
typedef std::back_insert_iterator<std::string> output_iterator_type;
typedef dump_ast<output_iterator_type> dump_ast;
dump_ast ast_grammar;
std::string str;
while (std::getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
expression_ast ast;
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
bool r = qi::phrase_parse(iter, end, calc, space, ast);
if (r && iter == end)
{
std::string generated;
output_iterator_type outit(generated);
r = karma::generate_delimited(outit, ast_grammar, space, ast);
if (r)
{
std::cout << "Got AST:" << std::endl << generated
<< std::endl;
std::cout << "-------------------------\n";
}
else
{
std::cout << "-------------------------\n";
std::cout << "Generating failed\n";
std::cout << "-------------------------\n";
}
}
else
{
std::string rest(iter, end);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << rest << "\"\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}

View File

@@ -0,0 +1,63 @@
// Copyright (c) 2001-2010 Hartmut Kaiser
//
// 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)
// The purpose of this example is to demonstrate different use cases for the
// confix generator.
#include <iostream>
#include <string>
#include <vector>
//[karma_confix_includes
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/repository/include/karma_confix.hpp>
//]
//[karma_confix_namespace
using namespace boost::spirit;
using namespace boost::spirit::ascii;
using boost::spirit::repository::confix;
//]
int main()
{
//[karma_confix_cpp_comment
// C++ comment
std::cout <<
karma::format_delimited(
confix("//", eol)[string], // format description
space, // delimiter
"This is a comment" // data
) << std::endl;
//]
//[karma_confix_c_comment
// C comment
std::cout <<
karma::format_delimited(
confix("/*", "*/")[string], // format description
space, // delimiter
"This is a comment" // data
) << std::endl;
//]
//[karma_confix_function
// Generate a function call with an arbitrary parameter list
std::vector<std::string> parameters;
parameters.push_back("par1");
parameters.push_back("par2");
parameters.push_back("par3");
std::cout <<
karma::format(
string << confix('(', ')')[string % ','], // format description
"func", // function name
parameters // parameter names
) << std::endl;
//]
return 0;
}

View File

@@ -0,0 +1,233 @@
/*=============================================================================
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)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// A mini XML-like parser, Karma is used to print out the generated AST
//
// [ JDG March 25, 2007 ] spirit2
// [ HK April 02, 2007 ] spirit2
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/qi.hpp>
//[mini_xml_karma_sr_includes
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/repository/include/karma_subrule.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/fusion.hpp>
//]
#include <boost/phoenix/function.hpp>
#include <boost/phoenix/stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
//[mini_xml_karma_sr_using
using namespace boost::spirit;
using namespace boost::spirit::ascii;
namespace repo = boost::spirit::repository;
//]
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
using phoenix::at_c;
using phoenix::push_back;
///////////////////////////////////////////////////////////////////////////////
// Our mini XML tree representation
///////////////////////////////////////////////////////////////////////////////
struct mini_xml;
typedef
boost::variant<
boost::recursive_wrapper<mini_xml>
, std::string
>
mini_xml_node;
struct mini_xml
{
std::string name; // tag name
std::vector<mini_xml_node> children; // children
};
// We need to tell fusion about our mini_xml struct
// to make it a first-class fusion citizen
BOOST_FUSION_ADAPT_STRUCT(
mini_xml,
(std::string, name)
(std::vector<mini_xml_node>, children)
)
///////////////////////////////////////////////////////////////////////////////
// Our mini XML grammar definition
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct mini_xml_parser :
qi::grammar<Iterator, mini_xml(), space_type>
{
mini_xml_parser() : mini_xml_parser::base_type(xml)
{
text = lexeme[+(char_ - '<') [_val += _1]];
node = (xml | text) [_val = _1];
start_tag =
'<'
>> !lit('/')
>> lexeme[+(char_ - '>') [_val += _1]]
>> '>'
;
end_tag =
"</"
>> lit(_r1)
>> '>'
;
xml =
start_tag [at_c<0>(_val) = _1]
>> *node [push_back(at_c<1>(_val), _1)]
>> end_tag(at_c<0>(_val))
;
}
qi::rule<Iterator, mini_xml(), space_type> xml;
qi::rule<Iterator, mini_xml_node(), space_type> node;
qi::rule<Iterator, std::string(), space_type> text;
qi::rule<Iterator, std::string(), space_type> start_tag;
qi::rule<Iterator, void(std::string), space_type> end_tag;
};
///////////////////////////////////////////////////////////////////////////////
// A couple of phoenix functions helping to access the elements of the
// generated AST
///////////////////////////////////////////////////////////////////////////////
template <typename T>
struct get_element
{
template <typename T1>
struct result { typedef T const& type; };
T const& operator()(mini_xml_node const& node) const
{
return boost::get<T>(node);
}
};
phoenix::function<get_element<std::string> > _string;
phoenix::function<get_element<mini_xml> > _xml;
///////////////////////////////////////////////////////////////////////////////
// The output grammar defining the format of the generated data
///////////////////////////////////////////////////////////////////////////////
//[mini_xml_karma_sr_grammar
template <typename OutputIterator>
struct mini_xml_generator
: karma::grammar<OutputIterator, mini_xml()>
{
mini_xml_generator() : mini_xml_generator::base_type(entry)
{
entry %= (
xml =
'<' << string[_1 = at_c<0>(_val)] << '>'
<< (*node)[_1 = at_c<1>(_val)]
<< "</" << string[_1 = at_c<0>(_val)] << '>'
, node %= string | xml
);
}
karma::rule<OutputIterator, mini_xml()> entry;
repo::karma::subrule<0, mini_xml()> xml;
repo::karma::subrule<1, mini_xml_node()> node;
};
//]
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
char const* filename;
if (argc > 1)
{
filename = argv[1];
}
else
{
std::cerr << "Error: No input file provided." << std::endl;
return 1;
}
std::ifstream in(filename, std::ios_base::in);
if (!in)
{
std::cerr << "Error: Could not open input file: "
<< filename << std::endl;
return 1;
}
std::string storage; // We will read the contents here.
in.unsetf(std::ios::skipws); // No white space skipping!
std::copy(
std::istream_iterator<char>(in),
std::istream_iterator<char>(),
std::back_inserter(storage));
typedef mini_xml_parser<std::string::const_iterator> mini_xml_parser;
mini_xml_parser xmlin; // Our grammar definition
mini_xml ast; // our tree
std::string::const_iterator iter = storage.begin();
std::string::const_iterator end = storage.end();
bool r = qi::phrase_parse(iter, end, xmlin, space, ast);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "-------------------------\n";
typedef std::back_insert_iterator<std::string> outiter_type;
typedef mini_xml_generator<outiter_type> mini_xml_generator;
mini_xml_generator xmlout; // Our grammar definition
std::string generated;
outiter_type outit(generated);
bool r = karma::generate(outit, xmlout, ast);
if (r)
std::cout << generated << std::endl;
return 0;
}
else
{
std::string::const_iterator begin = storage.begin();
std::size_t dist = std::distance(begin, iter);
std::string::const_iterator some =
iter + (std::min)(storage.size()-dist, std::size_t(30));
std::string context(iter, some);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << context << "...\"\n";
std::cout << "-------------------------\n";
return 1;
}
}

View File

@@ -0,0 +1,23 @@
#==============================================================================
# Copyright (c) 2001-2009 Joel de Guzman
# Copyright (c) 2001-2009 Hartmut Kaiser
#
# 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)
#==============================================================================
project spirit_v2_repository/example_qi
: requirements
<c++-template-depth>300
;
exe qi_confix : confix.cpp ;
exe qi_distinct : distinct.cpp ;
exe flush_multi_pass : flush_multi_pass.cpp ;
exe calc1_sr : calc1_sr.cpp ;
exe mini_xml2_sr : mini_xml2_sr.cpp ;
exe advance : advance.cpp ;
exe keywords : keywords.cpp ;
exe derived : derived.cpp ;
exe options : options.cpp ;
exe seek : seek.cpp ;

View File

@@ -0,0 +1,110 @@
// Copyright (c) 2011 Aaron Graham
//
// 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)
// The purpose of this example is to demonstrate the use of the advance parser.
//[qi_advance_includes
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/spirit/repository/include/qi_advance.hpp>
//]
#include <list>
#include <string>
//[qi_advance_namespaces
namespace qi = boost::spirit::qi;
using boost::spirit::repository::qi::advance;
//]
namespace client
{
//[qi_advance_grammar
template <typename Iterator>
struct advance_grammar : qi::grammar<Iterator, qi::locals<int> >
{
advance_grammar() : advance_grammar::base_type(start)
{
using qi::byte_;
using qi::eoi;
using namespace qi::labels;
start
= byte_ [_a = _1]
>> advance(_a)
>> "boost"
>> byte_ [_a = _1]
>> (advance(_a) | "qi") // note alternative when advance fails
>> eoi
;
}
qi::rule<Iterator, qi::locals<int> > start;
};
//]
}
int main()
{
// This parser is tested with both random access iterators (std::string)
// and bidirectional iterators (std::list).
char const* result;
//[qi_advance_example1
unsigned char const alt1[] =
{
5, // number of bytes to advance
1, 2, 3, 4, 5, // data to advance through
'b', 'o', 'o', 's', 't', // word to parse
2, // number of bytes to advance
11, 12 // more data to advance through
// eoi
};
std::string const alt1_string(alt1, alt1 + sizeof alt1);
std::list<unsigned char> const alt1_list(alt1, alt1 + sizeof alt1);
result =
qi::parse(alt1_string.begin(), alt1_string.end()
, client::advance_grammar<std::string::const_iterator>())
? "succeeded" : "failed";
std::cout << "Parsing alt1 using random access iterator " << result << std::endl;
result =
qi::parse(alt1_list.begin(), alt1_list.end()
, client::advance_grammar<std::list<unsigned char>::const_iterator>())
? "succeeded" : "failed";
std::cout << "Parsing alt1 using bidirectional iterator " << result << std::endl;
//]
//[qi_advance_example2
unsigned char const alt2[] =
{
2, // number of bytes to advance
1, 2, // data to advance through
'b', 'o', 'o', 's', 't', // word to parse
4, // number of bytes to advance
'q', 'i' // alternative (advance won't work)
// eoi
};
std::string const alt2_string(alt2, alt2 + sizeof alt2);
std::list<unsigned char> const alt2_list(alt2, alt2 + sizeof alt2);
result =
qi::parse(alt2_string.begin(), alt2_string.end()
, client::advance_grammar<std::string::const_iterator>())
? "succeeded" : "failed";
std::cout << "Parsing alt2 using random access iterator " << result << std::endl;
result =
qi::parse(alt2_list.begin(), alt2_list.end()
, client::advance_grammar<std::list<unsigned char>::const_iterator>())
? "succeeded" : "failed";
std::cout << "Parsing alt2 using bidirectional iterator " << result << std::endl;
//]
return 0;
}

View File

@@ -0,0 +1,117 @@
/*=============================================================================
Copyright (c) 2001-2010 Joel de Guzman
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)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// Plain calculator example demonstrating the grammar. The parser is a
// syntax checker only and does not do any semantic evaluation.
//
// [ JDG May 10, 2002 ] spirit1
// [ JDG March 4, 2007 ] spirit2
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_subrule.hpp>
#include <iostream>
#include <string>
namespace client
{
namespace qi = boost::spirit::qi;
namespace repo = boost::spirit::repository;
namespace ascii = boost::spirit::ascii;
///////////////////////////////////////////////////////////////////////////////
// Our calculator grammar
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct calculator : qi::grammar<Iterator, ascii::space_type>
{
calculator() : calculator::base_type(entry)
{
using qi::uint_;
//[calc1_sr_def
entry = (
expression =
term
>> *( ('+' >> term)
| ('-' >> term)
)
, term =
factor
>> *( ('*' >> factor)
| ('/' >> factor)
)
, factor =
uint_
| '(' >> expression >> ')'
| ('-' >> factor)
| ('+' >> factor)
);
//]
}
qi::rule<Iterator, ascii::space_type> entry;
repo::qi::subrule<0> expression;
repo::qi::subrule<1> term;
repo::qi::subrule<2> factor;
};
}
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int
main()
{
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "Expression parser...\n\n";
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "Type an expression...or [q or Q] to quit\n\n";
using boost::spirit::ascii::space;
typedef std::string::const_iterator iterator_type;
typedef client::calculator<iterator_type> calculator;
calculator calc; // Our grammar
std::string str;
while (std::getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
bool r = phrase_parse(iter, end, calc, space);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "-------------------------\n";
}
else
{
std::string rest(iter, end);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << rest << "\"\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}

View File

@@ -0,0 +1,113 @@
// Copyright (c) 2009 Chris Hoeppler
//
// 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)
// The purpose of this example is to demonstrate different use cases for the
// confix directive.
#include <iostream>
#include <string>
#include <vector>
//[qi_confix_includes
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_confix.hpp>
//]
namespace client {
//[qi_confix_using
using boost::spirit::eol;
using boost::spirit::lexeme;
using boost::spirit::ascii::alnum;
using boost::spirit::ascii::char_;
using boost::spirit::ascii::space;
using boost::spirit::qi::parse;
using boost::spirit::qi::phrase_parse;
using boost::spirit::repository::confix;
//]
//[qi_confix_cpp_comment
template <typename Iterator>
bool parse_cpp_comment(Iterator first, Iterator last, std::string& attr)
{
bool r = parse(first, last,
confix("//", eol)[*(char_ - eol)], // grammar
attr); // attribute
if (!r || first != last) // fail if we did not get a full match
return false;
return r;
}
//]
//[qi_confix_c_comment
template <typename Iterator>
bool parse_c_comment(Iterator first, Iterator last, std::string& attr)
{
bool r = parse(first, last,
confix("/*", "*/")[*(char_ - "*/")], // grammar
attr); // attribute
if (!r || first != last) // fail if we did not get a full match
return false;
return r;
}
//]
//[qi_confix_tagged_data
template <typename Iterator>
bool parse_tagged(Iterator first, Iterator last, std::string& attr)
{
bool r = phrase_parse(first, last,
confix("<b>", "</b>")[lexeme[*(char_ - '<')]], // grammar
space, // skip
attr); // attribute
if (!r || first != last) // fail if we did not get a full match
return false;
return r;
}
//]
}
int main()
{
// C++ comment
std::string comment("// This is a comment\n");
std::string attr;
bool r = client::parse_cpp_comment(comment.begin(), comment.end(), attr);
std::cout << "Parsing a C++ comment";
if (r && attr == " This is a comment")
std::cout << " succeeded." << std::endl;
else
std::cout << " failed" << std::endl;
// C comment
comment = "/* This is another comment */";
attr.clear();
r = client::parse_c_comment(comment.begin(), comment.end(), attr);
std::cout << "Parsing a C comment";
if (r && attr == " This is another comment ")
std::cout << " succeeded." << std::endl;
else
std::cout << " failed" << std::endl;
// Tagged data
std::string data = "<b> This is the body. </b>";
attr.clear();
r = client::parse_tagged(data.begin(), data.end(), attr);
std::cout << "Parsing tagged data";
if (r && attr == "This is the body. ")
std::cout << " succeeded." << std::endl;
else
std::cout << " failed" << std::endl;
return 0;
}

View File

@@ -0,0 +1,159 @@
/*=============================================================================
Copyright (c) 2011 Thomas Bernard
http://spirit.sourceforge.net/
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)
=============================================================================*/
//[reference_includes
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/stl/container.hpp>
#include <boost/phoenix/object.hpp>
#include <boost/phoenix/fusion.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/repository/include/qi_kwd.hpp>
#include <boost/spirit/repository/include/qi_keywords.hpp>
#include <iostream>
#include <string>
#include <cstdlib>
#include <iterator>
//]
// Data structure definitions
struct base_type {
base_type(const std::string &name) : name(name) {}
std::string name;
virtual ~base_type() {}
virtual std::ostream &output(std::ostream &os) const
{
os<<"Base : "<<name;
return os;
}
};
struct derived1 : public base_type {
derived1(const std::string &name, unsigned int data1) : base_type(name), data1(data1) {}
unsigned int data1;
virtual std::ostream &output(std::ostream &os) const
{
base_type::output(os);
os<<", "<<data1;
return os;
}
};
struct derived2 : public base_type {
derived2(const std::string &name, unsigned int data2) : base_type(name), data2(data2) {}
unsigned int data2;
virtual std::ostream &output(std::ostream &os) const
{
base_type::output(os);
os<<", "<<data2;
return os;
}
};
struct derived3 : public derived2 {
derived3(const std::string &name, unsigned int data2, double data3) :
derived2(name,data2),
data3(data3) {}
double data3;
virtual std::ostream &output(std::ostream &os) const
{
derived2::output(os);
os<<", "<<data3;
return os;
}
};
std::ostream &operator<<(std::ostream &os, const base_type &obj)
{
return obj.output(os);
}
BOOST_FUSION_ADAPT_STRUCT( base_type,
(std::string, name)
)
BOOST_FUSION_ADAPT_STRUCT( derived1,
(std::string , name)
(unsigned int , data1)
)
BOOST_FUSION_ADAPT_STRUCT( derived2,
(std::string , name)
(unsigned int, data2)
)
BOOST_FUSION_ADAPT_STRUCT( derived3,
(std::string , name)
(unsigned int, data2)
(double, data3)
)
//]
int
main()
{
using boost::spirit::repository::qi::kwd;
using boost::spirit::qi::inf;
using boost::spirit::ascii::space_type;
using boost::spirit::ascii::char_;
using boost::spirit::qi::double_;
using boost::spirit::qi::int_;
using boost::spirit::qi::rule;
using boost::spirit::_val;
using boost::spirit::_1;
using boost::spirit::_2;
using boost::spirit::_3;
//Rule declarations
rule<const char *, std::string(), space_type> parse_string;
rule<const char *, std::vector<base_type*>(), space_type> kwd_rule;
// Our string parsing helper
parse_string %= '"'> *(char_-'"') > '"';
namespace phx=boost::phoenix;
//[ kwd rule
kwd_rule =
kwd("derived1")[ ('=' > parse_string > int_ ) [phx::push_back(_val,phx::new_<derived1>(_1,_2))] ]
/ kwd("derived2")[ ('=' > parse_string > int_ ) [phx::push_back(_val,phx::new_<derived2>(_1,_2))]]
/ kwd("derived3")[ ('=' > parse_string > int_ > double_) [phx::push_back(_val,phx::new_<derived3>(_1,_2,_3))] ]
;
//]
using boost::spirit::qi::phrase_parse;
using boost::spirit::qi::ascii::space;
// The result vector
std::vector<base_type*> result;
char const input[]="derived2 = \"object1\" 10 derived3= \"object2\" 40 20.0 ";
char const* f(input);
char const* l(f + strlen(f));
if (phrase_parse(f, l, kwd_rule, space,result) && (f == l))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
using namespace boost::phoenix::arg_names;
std::for_each(result.begin(),result.end(),std::cout<<*arg1<<std::endl);
// Clean up the vector of pointers
std::for_each(result.begin(),result.end(),phx::delete_(arg1));
return 0;
}

View File

@@ -0,0 +1,60 @@
// Copyright (c) 2001-2010 Hartmut Kaiser
//
// 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)
// The purpose of this example is to demonstrate different use cases for the
// distinct parser.
#include <iostream>
#include <string>
#include <vector>
//[qi_distinct_includes
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_distinct.hpp>
//]
//[qi_distinct_namespace
using namespace boost::spirit;
using namespace boost::spirit::ascii;
using boost::spirit::repository::distinct;
//]
int main()
{
//[qi_distinct_description_ident
{
std::string str("description ident");
std::string::iterator first(str.begin());
bool r = qi::phrase_parse(first, str.end()
, distinct(alnum | '_')["description"] >> -lit("--") >> +(alnum | '_')
, space);
BOOST_ASSERT(r && first == str.end());
}
//]
//[qi_distinct_description__ident
{
std::string str("description--ident");
std::string::iterator first(str.begin());
bool r = qi::phrase_parse(first, str.end()
, distinct(alnum | '_')["description"] >> -lit("--") >> +(alnum | '_')
, space);
BOOST_ASSERT(r && first == str.end());
}
//]
//[qi_distinct_description_ident_error
{
std::string str("description-ident");
std::string::iterator first(str.begin());
bool r = qi::phrase_parse(first, str.end()
, distinct(alnum | '_')["description"] >> -lit("--") >> +(alnum | '_')
, space);
BOOST_ASSERT(!r && first == str.begin());
}
//]
return 0;
}

View File

@@ -0,0 +1,98 @@
// Copyright (c) 2001-2010 Hartmut Kaiser
//
// 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)
// The purpose of this example is to demonstrate a simple use case for the
// flush_multi_pass parser.
#include <iostream>
#include <fstream>
#include <string>
//[qi_flush_multi_pass_includes
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_flush_multi_pass.hpp>
//]
//[qi_flush_multi_pass_namespace
namespace spirit = boost::spirit;
using boost::spirit::repository::flush_multi_pass;
//]
namespace client
{
//[qi_flush_multi_pass_clear_buffer
template <typename Iterator, typename Skipper>
struct preprocessor : spirit::qi::grammar<Iterator, Skipper>
{
// This is a simplified preprocessor grammar recognizing
//
// #define MACRONAME something
// #undef MACRONAME
//
// Its sole purpose is to show an example how to use the
// flush_multi_pass parser. At the end of each line no backtracking can
// occur anymore so that it's safe to clear all internal buffers in the
// multi_pass.
preprocessor() : preprocessor::base_type(file)
{
using spirit::ascii::char_;
using spirit::qi::eol;
using spirit::qi::lit;
file =
*line
;
line = ( command | *(char_ - eol) )
>> eol
>> flush_multi_pass
;
command =
"#define" >> *lit(' ') >> *(char_ - ' ') >> *lit(' ') >> *(char_ - eol)
| "#undef" >> *lit(' ') >> *(char_ - eol)
;
}
spirit::qi::rule<Iterator, Skipper> file, line, command;
};
//]
}
template <typename Iterator, typename Skipper>
bool parse(Iterator& first, Iterator end, Skipper const& skipper)
{
client::preprocessor<Iterator, Skipper> g;
return boost::spirit::qi::phrase_parse(first, end, g, skipper);
}
int main()
{
namespace spirit = boost::spirit;
using spirit::ascii::char_;
using spirit::qi::eol;
std::ifstream in("flush_multi_pass.txt"); // we get our input from this file
if (!in.is_open()) {
std::cout << "Could not open input file: 'flush_multi_pass.txt'" << std::endl;
return -1;
}
typedef std::istreambuf_iterator<char> base_iterator_type;
spirit::multi_pass<base_iterator_type> first =
spirit::make_default_multi_pass(base_iterator_type(in));
spirit::multi_pass<base_iterator_type> end =
spirit::make_default_multi_pass(base_iterator_type());
bool result = parse(first, end, '#' >> *(char_ - eol) >> eol);
if (!result) {
std::cout << "Failed parsing input file!" << std::endl;
return -2;
}
std::cout << "Successfully parsed input file!" << std::endl;
return 0;
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2001-2009 Hartmut Kaiser
#
# 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)
#define MACRO foo
#undef MACRO

View File

@@ -0,0 +1,51 @@
// Copyright (c) 2001-2010 Hartmut Kaiser
//
// 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)
// The purpose of this example is to show how a simple custom primitive parser
// component can be written. We develop a custom parser exposing the current
// iterator position as its attribute.
//
// For more information see: http://spirit.sourceforge.net/home/?page_id=567
#include <boost/spirit/include/qi_parse_attr.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/repository/include/qi_iter_pos.hpp>
#include <string>
namespace qi = boost::spirit::qi;
int main()
{
using boost::spirit::repository::qi::iter_pos;
std::string prefix, suffix; // attributes receiving the
std::string::iterator position; // parsed values
std::string input("prefix1234567");
std::string::iterator first = input.begin();
bool result =
qi::parse(first, input.end()
, +qi::alpha >> iter_pos >> +qi::digit
, prefix, position, suffix);
if (result)
{
std::cout << "-------------------------------- \n";
std::cout << "Parsing succeeded\n";
std::cout << "prefix is: " << prefix << "\n";
std::cout << "suffix is: " << suffix << "\n";
std::cout << "position is: " << std::distance(input.begin(), position) << "\n";
std::cout << "-------------------------------- \n";
}
else
{
std::cout << "-------------------------------- \n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------------- \n";
}
return 0;
}

View File

@@ -0,0 +1,214 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
http://spirit.sourceforge.net/
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)
=============================================================================*/
//[reference_includes
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/repository/include/qi_kwd.hpp>
#include <boost/spirit/repository/include/qi_keywords.hpp>
#include <iostream>
#include <string>
#include <cstdlib>
#include <iterator>
//]
//[reference_test
template <typename P>
void test_parser(
char const* input, P const& p, bool full_match = true)
{
using boost::spirit::qi::parse;
char const* f(input);
char const* l(f + strlen(f));
if (parse(f, l, p) && (!full_match || (f == l)))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
}
template <typename P>
void test_phrase_parser(
char const* input, P const& p, bool full_match = true)
{
using boost::spirit::qi::phrase_parse;
using boost::spirit::qi::ascii::space;
char const* f(input);
char const* l(f + strlen(f));
if (phrase_parse(f, l, p, space) && (!full_match || (f == l)))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
}
//]
//[reference_test_attr
template <typename P, typename T>
void test_parser_attr(
char const* input, P const& p, T& attr, bool full_match = true)
{
using boost::spirit::qi::parse;
char const* f(input);
char const* l(f + strlen(f));
if (parse(f, l, p, attr) && (!full_match || (f == l)))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
}
template <typename P, typename T>
void test_phrase_parser_attr(
char const* input, P const& p, T& attr, bool full_match = true)
{
using boost::spirit::qi::phrase_parse;
using boost::spirit::qi::ascii::space;
char const* f(input);
char const* l(f + strlen(f));
if (phrase_parse(f, l, p, space, attr) && (!full_match || (f == l)))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
}
//]
//[reference_keyword_list_test_data_structure
// Data structure definitions to test the kwd directive
// and the keywords list operator
struct person {
std::string name;
int age;
double size;
std::vector<std::string> favorite_colors;
};
std::ostream &operator<<(std::ostream &os, const person &p)
{
os<<"Person : "<<p.name<<", "<<p.age<<", "<<p.size<<std::endl;
std::copy(p.favorite_colors.begin(),p.favorite_colors.end(),std::ostream_iterator<std::string>(os,"\n"));
return os;
}
BOOST_FUSION_ADAPT_STRUCT( person,
(std::string, name)
(int, age)
(double, size)
(std::vector<std::string>, favorite_colors)
)
//]
int
main()
{
// keyword_list
{
//[reference_using_declarations_keyword_list
using boost::spirit::repository::qi::kwd;
using boost::spirit::qi::inf;
using boost::spirit::ascii::space_type;
using boost::spirit::ascii::char_;
using boost::spirit::qi::double_;
using boost::spirit::qi::int_;
using boost::spirit::qi::rule;
//]
//[reference_keyword_list_rule_declarations
rule<const char *, std::string(), space_type> parse_string;
rule<const char *, person(), space_type> no_constraint_person_rule, constraint_person_rule;
parse_string %= '"'> *(char_-'"') > '"';
//]
//[reference_keyword_list_no_constraint_rule
no_constraint_person_rule %=
kwd("name")['=' > parse_string ]
/ kwd("age") ['=' > int_]
/ kwd("size") ['=' > double_ > 'm']
;
//]
//[reference_keyword_list
//`Parsing a keyword list:
// Let's declare a small list of people for which we want to collect information.
person John,Mary,Mike,Hellen,Johny;
test_phrase_parser_attr(
"name = \"John\" \n age = 10 \n size = 1.69m "
,no_constraint_person_rule
,John); // full in original order
std::cout<<John;
test_phrase_parser_attr(
"age = 10 \n size = 1.69m \n name = \"Mary\""
,no_constraint_person_rule
,Mary); // keyword oder doesn't matter
std::cout<<Mary;
test_phrase_parser_attr(
"size = 1.69m \n name = \"Mike\" \n age = 10 "
,no_constraint_person_rule
,Mike); // still the same result
std::cout<<Mike;
/*`The code above will print:[teletype]
Person : John, 10, 1.69
Person : Mary, 10, 1.69
Person : Mike, 10, 1.69
*/
//]
//[reference_keyword_list_constraint_rule
/*`The parser definition below uses the kwd directive occurrence constraint variants to
make sure that the name and age keyword occur only once and allows the favorite color
entry to appear 0 or more times. */
constraint_person_rule %=
kwd("name",1) ['=' > parse_string ]
/ kwd("age" ,1) ['=' > int_]
/ kwd("size" ,1) ['=' > double_ > 'm']
/ kwd("favorite color",0,inf) [ '=' > parse_string ]
;
//]
//[reference_keyword_list_constraints
// Here all the give constraint are resepected : parsing will succeed.
test_phrase_parser_attr(
"name = \"Hellen\" \n age = 10 \n size = 1.80m \n favorite color = \"blue\" \n favorite color = \"green\" "
,constraint_person_rule
,Hellen);
std::cout<<Hellen;
// Parsing this string will fail because the age and size minimum occurrence requirements aren't met.
test_phrase_parser_attr(
"name = \"Johny\" \n favorite color = \"blue\" \n favorite color = \"green\" "
,constraint_person_rule
,Johny );
/*`Parsing the first string will succeed but fail for the second string as the
occurrence constraints aren't met. This code should print:[teletype]
Person : Hellen, 10, 1.8
blue
green
*/
//]
}
return 0;
}

View File

@@ -0,0 +1,245 @@
/*=============================================================================
Copyright (c) 2001-2010 Joel de Guzman
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)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// A mini XML-like parser
//
// [ JDG March 25, 2007 ] spirit2
//
///////////////////////////////////////////////////////////////////////////////
//[mini_xml2_sr_includes
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_subrule.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
//]
#include <boost/phoenix/fusion.hpp>
#include <boost/phoenix/stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
namespace client
{
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
//[mini_xml2_sr_using
namespace qi = boost::spirit::qi;
namespace repo = boost::spirit::repository;
namespace ascii = boost::spirit::ascii;
//]
///////////////////////////////////////////////////////////////////////////
// Our mini XML tree representation
///////////////////////////////////////////////////////////////////////////
struct mini_xml;
typedef
boost::variant<
boost::recursive_wrapper<mini_xml>
, std::string
>
mini_xml_node;
struct mini_xml
{
std::string name; // tag name
std::vector<mini_xml_node> children; // children
};
}
// We need to tell fusion about our mini_xml struct
// to make it a first-class fusion citizen
BOOST_FUSION_ADAPT_STRUCT(
client::mini_xml,
(std::string, name)
(std::vector<client::mini_xml_node>, children)
)
namespace client
{
///////////////////////////////////////////////////////////////////////////
// Print out the mini xml tree
///////////////////////////////////////////////////////////////////////////
int const tabsize = 4;
void tab(int indent)
{
for (int i = 0; i < indent; ++i)
std::cout << ' ';
}
struct mini_xml_printer
{
mini_xml_printer(int indent = 0)
: indent(indent)
{
}
void operator()(mini_xml const& xml) const;
int indent;
};
struct mini_xml_node_printer : boost::static_visitor<>
{
mini_xml_node_printer(int indent = 0)
: indent(indent)
{
}
void operator()(mini_xml const& xml) const
{
mini_xml_printer(indent+tabsize)(xml);
}
void operator()(std::string const& text) const
{
tab(indent+tabsize);
std::cout << "text: \"" << text << '"' << std::endl;
}
int indent;
};
void mini_xml_printer::operator()(mini_xml const& xml) const
{
tab(indent);
std::cout << "tag: " << xml.name << std::endl;
tab(indent);
std::cout << '{' << std::endl;
BOOST_FOREACH(mini_xml_node const& node, xml.children)
{
boost::apply_visitor(mini_xml_node_printer(indent), node);
}
tab(indent);
std::cout << '}' << std::endl;
}
///////////////////////////////////////////////////////////////////////////
// Our mini XML grammar definition
///////////////////////////////////////////////////////////////////////////
//[mini_xml2_sr_grammar
template <typename Iterator>
struct mini_xml_grammar
: qi::grammar<Iterator, mini_xml(), ascii::space_type>
{
mini_xml_grammar()
: mini_xml_grammar::base_type(entry)
{
using qi::lit;
using qi::lexeme;
using ascii::char_;
using ascii::string;
using namespace qi::labels;
entry %= (
xml %=
start_tag[_a = _1]
>> *node
>> end_tag(_a)
, node %= xml | text
, text %= lexeme[+(char_ - '<')]
, start_tag %=
'<'
>> !lit('/')
>> lexeme[+(char_ - '>')]
>> '>'
, end_tag %=
"</"
>> lit(_r1)
>> '>'
);
}
qi::rule<Iterator, mini_xml(), ascii::space_type> entry;
repo::qi::subrule<0, mini_xml(), qi::locals<std::string> > xml;
repo::qi::subrule<1, mini_xml_node()> node;
repo::qi::subrule<2, std::string()> text;
repo::qi::subrule<3, std::string()> start_tag;
repo::qi::subrule<4, void(std::string)> end_tag;
};
//]
}
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
char const* filename;
if (argc > 1)
{
filename = argv[1];
}
else
{
std::cerr << "Error: No input file provided." << std::endl;
return 1;
}
std::ifstream in(filename, std::ios_base::in);
if (!in)
{
std::cerr << "Error: Could not open input file: "
<< filename << std::endl;
return 1;
}
std::string storage; // We will read the contents here.
in.unsetf(std::ios::skipws); // No white space skipping!
std::copy(
std::istream_iterator<char>(in),
std::istream_iterator<char>(),
std::back_inserter(storage));
typedef client::mini_xml_grammar<std::string::const_iterator> mini_xml_grammar;
mini_xml_grammar xml; // Our grammar
client::mini_xml ast; // Our tree
using boost::spirit::ascii::space;
std::string::const_iterator iter = storage.begin();
std::string::const_iterator end = storage.end();
bool r = phrase_parse(iter, end, xml, space, ast);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "-------------------------\n";
client::mini_xml_printer printer;
printer(ast);
return 0;
}
else
{
std::string::const_iterator some = iter + std::min(30, int(end - iter));
std::string context(iter, (some>end)?end:some);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \"" << context << "...\"\n";
std::cout << "-------------------------\n";
return 1;
}
}

View File

@@ -0,0 +1,122 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
http://spirit.sourceforge.net/
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)
=============================================================================*/
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/repository/include/qi_kwd.hpp>
#include <boost/spirit/repository/include/qi_keywords.hpp>
#include <boost/optional.hpp>
#include <boost/cstdint.hpp>
#include <iostream>
#include <string>
#include <cstdlib>
#include <iterator>
#include <map>
#include <vector>
// Data structure definitions
// preprocessor constants
typedef std::pair<std::string, boost::int32_t> preprocessor_symbol;
BOOST_FUSION_ADAPT_STRUCT( preprocessor_symbol,
(std::string, first)
(boost::int32_t, second)
)
// A data structure to store our program options
struct program_options {
std::vector<std::string> includes; // include paths
typedef std::vector< preprocessor_symbol > preprocessor_symbols_container; // symbol container type definition
preprocessor_symbols_container preprocessor_symbols; // preprocessor symbols
boost::optional<std::string> output_filename; // output file name
std::string source_filename; // source file name
};
// Make the program_options compatible with fusion sequences
BOOST_FUSION_ADAPT_STRUCT( program_options,
(std::vector<std::string>, includes)
(program_options::preprocessor_symbols_container, preprocessor_symbols)
(boost::optional<std::string>, output_filename)
(std::string, source_filename)
)
// Output helper to check that the data parsed matches what we expect
std::ostream &operator<<(std::ostream &os, const program_options &obj)
{
using boost::spirit::karma::string;
using boost::spirit::karma::int_;
using boost::spirit::karma::lit;
using boost::spirit::karma::buffer;
using boost::spirit::karma::eol;
using boost::spirit::karma::format;
return os<<format(
lit("Includes:") << (string % ',') << eol
<< lit("Preprocessor symbols:") << ((string <<"="<< int_) % ',') << eol
<< buffer[-( lit("Output file:")<< string << eol)]
<< lit("Source file:")<< string << eol
,obj);
return os;
}
int
main()
{
{
// Pull everything we need from qi into this scope
using boost::spirit::repository::qi::kwd;
using boost::spirit::qi::inf;
using boost::spirit::ascii::space_type;
using boost::spirit::ascii::alnum;
using boost::spirit::qi::int_;
using boost::spirit::qi::rule;
using boost::spirit::qi::lit;
using boost::spirit::qi::attr;
using boost::spirit::qi::lexeme;
using boost::spirit::qi::hold;
using boost::spirit::qi::ascii::space;
//Rule declarations
rule<const char *, std::string(), space_type> parse_string;
rule<const char *, program_options(), space_type> kwd_rule;
// A string parser
parse_string %= lexeme[*alnum];
namespace phx=boost::phoenix;
// kwd rule
kwd_rule %=
kwd("--include")[ parse_string ]
/ kwd("--define")[ parse_string >> ((lit('=') > int_) | attr(1)) ]
/ kwd("--output",0,1)[ parse_string ]
/ hold [kwd("--source",1)[ parse_string ]]
;
//
using boost::spirit::qi::phrase_parse;
// Let's check what that parser can do
program_options result;
char const input[]="--include path1 --source file1 --define SYMBOL1=10 --include path2 --source file2";
char const* f(input);
char const* l(f + strlen(f));
if (phrase_parse(f, l, kwd_rule, space,result) && (f == l))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
// Output the result to the console
std::cout<<result<<std::endl;
}
return 0;
}

View File

@@ -0,0 +1,48 @@
/*//////////////////////////////////////////////////////////////////////////////
Copyright (c) 2011 Jamboree
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)
//////////////////////////////////////////////////////////////////////////////*/
// [ Jamboree Oct 27, 2011 ] new example.
#include <cstdlib>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_seek.hpp>
int main()
{
//[reference_qi_seek_namespace
namespace qi = boost::spirit::qi;
namespace repo = boost::spirit::repository;
//]
typedef std::string::const_iterator iterator;
//[reference_qi_seek_vars
std::string str("/*C-style comment*/");
iterator it = str.begin();
iterator end = str.end();
//]
//[reference_qi_seek_parse
if (qi::parse(it, end, "/*" >> repo::qi::seek["*/"]))
{
std::cout << "-------------------------------- \n";
std::cout << "Parsing succeeded.\n";
std::cout << "---------------------------------\n";
}
else
{
std::cout << "-------------------------------- \n";
std::cout << "Unterminated /* comment.\n";
std::cout << "-------------------------------- \n";
}//]
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,15 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
</head>
<body>
Automatic redirection failed, click this
<a href="doc/html/index.html">link</a> &nbsp;<hr>
<p><EFBFBD> Copyright Beman Dawes, 2001</p>
<p>Distributed under the Boost Software License, Version 1.0. (See
accompanying file <a href="../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p>
</body>
</html>

View File

@@ -0,0 +1,19 @@
{
"key": "spirit/repository",
"name": "Spirit Repository",
"authors": [
"Joel de Guzman",
"Hartmut Kaiser",
"Dan Nuffer"
],
"description": "The Spirit repository is a community effort collecting different reusable components (primitives, directives, grammars, etc.) for Qi parsers and Karma generators.",
"category": [
"Parsing",
"String"
],
"maintainers": [
"Joel de Guzman <joel -at- boost-consulting.com>",
"Hartmut Kaiser <hartmut.kaiser -at- gmail.com>"
],
"cxxstd": "03"
}

View File

@@ -0,0 +1,59 @@
#==============================================================================
# Copyright (c) 2001-2009 Joel de Guzman
# Copyright (c) 2001-2009 Hartmut Kaiser
# Copyright (c) 2017-2019 Nikita Kniazev
#
# Use, modification and distribution is subject to 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)
#==============================================================================
local 9-11 = 9 10 11 ;
project spirit_v2_repository/test
: requirements
<include>.
<c++-template-depth>300
<known-warnings>hide,<toolset>gcc-$(9-11):<cxxflags>-Wno-deprecated-copy # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94492
:
:
;
###############################################################################
alias qi-pch : : <pch>on-spirit:<source>../../test/qi//pch ;
alias ka-pch : : <pch>on-spirit:<source>../../test/karma//pch ;
explicit qi-pch ka-pch ;
###############################################################################
import os ;
local keywords_reqs ;
if [ os.environ APPVEYOR ]
{
# Workaround MSVC codegen bug. See #400 for the info.
keywords_reqs = <toolset>msvc-14.1:<inlining>off ;
}
# bring in rules for testing
import testing ;
{
test-suite spirit_v2_repository :
# run Qi repository tests
[ run qi-pch qi/advance.cpp : : : : qi_repo_advance ]
[ run qi-pch qi/confix.cpp : : : : qi_repo_confix ]
[ run qi-pch qi/distinct.cpp : : : : qi_repo_distinct ]
[ run qi-pch qi/subrule.cpp : : : : qi_repo_subrule ]
[ run qi-pch qi/keywords.cpp : : : $(keywords_reqs) : qi_repo_keywords ]
[ run qi-pch qi/seek.cpp : : : : qi_repo_seek ]
# run Karma repository tests
[ run ka-pch karma/confix.cpp : : : : karma_repo_confix ]
[ run ka-pch karma/subrule.cpp : : : : karma_repo_subrule ]
;
}

View File

@@ -0,0 +1,121 @@
// Copyright (c) 2001-2010 Hartmut Kaiser
//
// 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)
#include <boost/spirit/repository/include/karma_confix.hpp>
#include <boost/spirit/include/karma_auxiliary.hpp>
#include <boost/spirit/include/karma_char.hpp>
#include <boost/spirit/include/karma_string.hpp>
#include <boost/spirit/include/karma_generate.hpp>
#include <iostream>
#include "test.hpp"
namespace html
{
namespace spirit = boost::spirit;
namespace repo = boost::spirit::repository;
///////////////////////////////////////////////////////////////////////////////
// define a HTML tag helper generator
namespace traits
{
template <typename Prefix, typename Suffix = Prefix>
struct confix_spec
: spirit::result_of::terminal<repo::tag::confix(Prefix, Suffix)>
{};
}
template <typename Prefix, typename Suffix>
inline typename traits::confix_spec<Prefix, Suffix>::type
confix_spec(Prefix const& prefix, Suffix const& suffix)
{
return repo::confix(prefix, suffix);
}
///////////////////////////////////////////////////////////////////////////
template <typename Char, typename Traits, typename Allocator>
inline typename traits::confix_spec<
std::basic_string<Char, Traits, Allocator>
>::type
tag (std::basic_string<Char, Traits, Allocator> const& tagname)
{
typedef std::basic_string<Char, Traits, Allocator> string_type;
return confix_spec(string_type("<") + tagname + ">"
, string_type("</") + tagname + ">");
}
inline traits::confix_spec<std::string>::type
tag (char const* tagname)
{
return tag(std::string(tagname));
}
///////////////////////////////////////////////////////////////////////////
typedef traits::confix_spec<std::string>::type html_tag_type;
html_tag_type const ol = tag("ol");
}
///////////////////////////////////////////////////////////////////////////////
int main()
{
using namespace spirit_test;
using namespace boost::spirit;
using namespace boost::spirit::repository;
{
using namespace boost::spirit::ascii;
BOOST_TEST((test("<tag>a</tag>",
confix("<tag>", "</tag>")[char_('a')])));
BOOST_TEST((test("<tag>a</tag>",
confix("<tag>", "</tag>")[char_], 'a')));
BOOST_TEST((test("// some C++ comment\n",
confix(string("//"), eol)[" some C++ comment"])));
BOOST_TEST((test("// some C++ comment\n",
confix(string("//"), eol)[string], " some C++ comment")));
BOOST_TEST((test("<ol>some text</ol>", html::ol["some text"])));
BOOST_TEST((test("<ol>some text</ol>", html::ol[string], "some text")));
}
{
using namespace boost::spirit::standard_wide;
BOOST_TEST((test(L"<tag>a</tag>",
confix(L"<tag>", L"</tag>")[char_(L'a')])));
BOOST_TEST((test(L"// some C++ comment\n",
confix(string(L"//"), eol)[L" some C++ comment"])));
BOOST_TEST((test(L"<ol>some text</ol>", html::ol[L"some text"])));
}
{
using namespace boost::spirit::ascii;
BOOST_TEST((test_delimited("<tag> a </tag> ",
confix("<tag>", "</tag>")[char_('a')], space)));
BOOST_TEST((test_delimited("// some C++ comment \n ",
confix(string("//"), eol)["some C++ comment"], space)));
BOOST_TEST((test_delimited("<ol> some text </ol> ",
html::ol["some text"], space)));
}
{
using namespace boost::spirit::standard_wide;
BOOST_TEST((test_delimited(L"<tag> a </tag> ",
confix(L"<tag>", L"</tag>")[char_(L'a')], space)));
BOOST_TEST((test_delimited(L"// some C++ comment \n ",
confix(string(L"//"), eol)[L"some C++ comment"], space)));
BOOST_TEST((test_delimited(L"<ol> some text </ol> ",
html::ol[L"some text"], space)));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,183 @@
// 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)
#include <boost/spirit/repository/include/karma_subrule.hpp>
#include <boost/spirit/include/karma_operator.hpp>
#include <boost/spirit/include/karma_char.hpp>
#include <boost/spirit/include/karma_auxiliary.hpp>
#include <boost/spirit/include/karma_string.hpp>
#include <boost/spirit/include/karma_numeric.hpp>
#include <boost/spirit/include/karma_nonterminal.hpp>
#include <boost/spirit/include/karma_action.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/statement.hpp>
#include <boost/phoenix/fusion.hpp>
#include "test.hpp"
using namespace spirit_test;
///////////////////////////////////////////////////////////////////////////////
int main()
{
using namespace boost;
using namespace boost::spirit;
using namespace boost::spirit::karma;
// using namespace boost::spirit::ascii;
using boost::spirit::repository::karma::subrule;
typedef spirit_test::output_iterator<char>::type outiter_type;
// basic tests
{
rule<outiter_type> start;
subrule<0> sr;
start = (
sr = char_[_1 = 'a'] << int_[_1 = 10] << double_[_1 = 12.4]
);
BOOST_TEST(test("a1012.4", start));
BOOST_TEST(test("a1012.4", (
sr = (char_ << int_ << double_)[(_1 = 'a', _2 = 10, _3 = 12.4)]
)));
subrule<1> a;
subrule<2> b;
subrule<3> c;
start = (
sr = a << b << c
, a = char_[_1 = 'a']
, b = int_[_1 = 10]
, c = double_[_1 = 12.4]
);
BOOST_TEST(test("a1012.4", start));
}
// basic tests with delimiter
{
rule<outiter_type, space_type> start;
subrule<0> sr;
start = (
sr = char_[_1 = 'a'] << int_[_1 = 10] << double_[_1 = 12.4]
);
BOOST_TEST(test_delimited("a 10 12.4 ", start, space));
BOOST_TEST(test_delimited("a 10 12.4 ", (
sr = (char_ << int_ << double_)[(_1 = 'a', _2 = 10, _3 = 12.4)]
), space));
subrule<1> a;
subrule<2> b;
subrule<3> c;
start = (
sr = a << b << c
, a = char_[_1 = 'a']
, b = int_[_1 = 10]
, c = double_[_1 = 12.4]
);
BOOST_TEST(test_delimited("a 10 12.4 ", start, space));
}
// basic tests involving a direct parameter
{
typedef variant<char, int, double> var_type;
rule<outiter_type, var_type()> start;
subrule<0, var_type()> sr;
start = (
sr = (char_ | int_ | double_)[_1 = _r0]
)[_1 = _val];
var_type v ('a');
BOOST_TEST(test("a", start, v));
v = 10;
BOOST_TEST(test("10", start, v));
v = 12.4;
BOOST_TEST(test("12.4", start, v));
}
{
typedef variant<char, int, double> var_type;
rule<outiter_type, space_type, var_type()> start;
subrule<0, var_type()> sr;
start %= (
sr = (char_ | int_ | double_)[_1 = _r0]
);
var_type v ('a');
BOOST_TEST(test_delimited("a ", start, v, space));
v = 10;
BOOST_TEST(test_delimited("10 ", start, v, space));
v = 12.4;
BOOST_TEST(test_delimited("12.4 ", start, v, space));
}
{
rule<outiter_type, void(char, int, double)> start;
subrule<0, void(char, int, double)> sr;
start = (
sr = char_[_1 = _r1] << int_[_1 = _r2] << double_[_1 = _r3]
)(_r1, _r2, _r3);
BOOST_TEST(test("a1012.4", start('a', 10, 12.4)));
BOOST_TEST(test("a1012.4", (
sr = (char_ << int_ << double_)[(_1 = _r1, _2 = _r2, _3 = _r3)]
)('a', 10, 12.4)));
subrule<1, void(char, int, double)> entry;
subrule<2, void(char)> a;
subrule<3, void(int)> b;
subrule<4, void(double)> c;
start = (
entry = a(_r1) << b(_r2) << c(_r3)
, a = char_[_1 = _r1]
, b = int_[_1 = _r1]
, c = double_[_1 = _r1]
)(_r1, _r2, _r3);
BOOST_TEST(test("a1012.4", start('a', 10, 12.4)));
}
{
rule<outiter_type, space_type, void(char, int, double)> start;
subrule<0, void(char, int, double)> sr;
start = (
sr = char_[_1 = _r1] << int_[_1 = _r2] << double_[_1 = _r3]
)(_r1, _r2, _r3);
BOOST_TEST(test_delimited("a 10 12.4 ", start('a', 10, 12.4), space));
BOOST_TEST(test_delimited("a 10 12.4 ", (
sr = (char_ << int_ << double_)[(_1 = _r1, _2 = _r2, _3 = _r3)]
)('a', 10, 12.4), space));
subrule<1, void(char, int, double)> entry;
subrule<2, void(char)> a;
subrule<3, void(int)> b;
subrule<4, void(double)> c;
start = (
entry = a(_r1) << b(_r2) << c(_r3)
, a = char_[_1 = _r1]
, b = int_[_1 = _r1]
, c = double_[_1 = _r1]
)(_r1, _r2, _r3);
BOOST_TEST(test_delimited("a 10 12.4 ", start('a', 10, 12.4), space));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,299 @@
// Copyright (c) 2001-2010 Hartmut Kaiser
//
// 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)
#if !defined(BOOST_SPIRIT_KARMA_TEST_FEB_23_2007_1221PM)
#define BOOST_SPIRIT_KARMA_TEST_FEB_23_2007_1221PM
#include <cstring>
#include <string>
#include <iterator>
#include <iostream>
#include <typeinfo>
#include <boost/spirit/include/karma_generate.hpp>
#include <boost/spirit/include/karma_what.hpp>
#include <boost/core/lightweight_test.hpp>
namespace spirit_test
{
///////////////////////////////////////////////////////////////////////////
struct display_type
{
template<typename T>
void operator()(T const &) const
{
std::cout << typeid(T).name() << std::endl;
}
template<typename T>
static void print()
{
std::cout << typeid(T).name() << std::endl;
}
};
display_type const display = {};
///////////////////////////////////////////////////////////////////////////
template <typename Char>
struct output_iterator
{
typedef std::basic_string<Char> string_type;
typedef std::back_insert_iterator<string_type> type;
};
///////////////////////////////////////////////////////////////////////////
template <typename Char, typename T>
void print_if_failed(char const* func, bool result
, std::basic_string<Char> const& generated, T const& expected)
{
if (!result)
std::cerr << "in " << func << ": result is false" << std::endl;
else if (generated != expected)
std::cerr << "in " << func << ": generated \""
<< std::string(generated.begin(), generated.end())
<< "\"" << std::endl;
}
///////////////////////////////////////////////////////////////////////////
template <typename Char, typename Generator>
inline bool test(Char const *expected, Generator const& g)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<Char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate(outit, g);
print_if_failed("test", result, generated, expected);
return result && generated == expected;
}
template <typename Char, typename Generator>
inline bool test(std::basic_string<Char> const& expected, Generator const& g)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<Char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate(outit, g);
print_if_failed("test", result, generated, expected);
return result && generated == expected;
}
///////////////////////////////////////////////////////////////////////////
template <typename Char, typename Generator, typename Attribute>
inline bool test(Char const *expected, Generator const& g,
Attribute const &attr)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<Char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate(outit, g, attr);
print_if_failed("test", result, generated, expected);
return result && generated == expected;
}
template <typename Char, typename Generator, typename Attribute>
inline bool test(std::basic_string<Char> const& expected, Generator const& g,
Attribute const &attr)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<Char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate(outit, g, attr);
print_if_failed("test", result, generated, expected);
return result && generated == expected;
}
///////////////////////////////////////////////////////////////////////////
template <typename Char, typename Generator, typename Delimiter>
inline bool test_delimited(Char const *expected, Generator const& g,
Delimiter const& d)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<Char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate_delimited(outit, g, d);
print_if_failed("test_delimited", result, generated, expected);
return result && generated == expected;
}
template <typename Char, typename Generator, typename Delimiter>
inline bool test_delimited(std::basic_string<Char> const& expected,
Generator const& g, Delimiter const& d)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<Char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate_delimited(outit, g, d);
print_if_failed("test_delimited", result, generated, expected);
return result && generated == expected;
}
///////////////////////////////////////////////////////////////////////////
template <typename Char, typename Generator, typename Attribute,
typename Delimiter>
inline bool test_delimited(Char const *expected, Generator const& g,
Attribute const &attr, Delimiter const& d)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<Char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate_delimited(outit, g, d, attr);
print_if_failed("test_delimited", result, generated, expected);
return result && generated == expected;
}
template <typename Char, typename Generator, typename Attribute,
typename Delimiter>
inline bool test_delimited(std::basic_string<Char> const& expected,
Generator const& g, Attribute const &attr, Delimiter const& d)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<Char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate_delimited(outit, g, d, attr);
print_if_failed("test_delimited", result, generated, expected);
return result && generated == expected;
}
///////////////////////////////////////////////////////////////////////////
template <typename Generator>
inline bool
binary_test(char const *expected, std::size_t size,
Generator const& g)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate(outit, g);
return result && !std::memcmp(generated.c_str(), expected, size);
}
///////////////////////////////////////////////////////////////////////////
template <typename Generator, typename Attribute>
inline bool
binary_test(char const *expected, std::size_t size,
Generator const& g, Attribute const &attr)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate(outit, g, attr);
return result && !std::memcmp(generated.c_str(), expected, size);
}
///////////////////////////////////////////////////////////////////////////
template <typename Generator, typename Delimiter>
inline bool
binary_test_delimited(char const *expected, std::size_t size,
Generator const& g, Delimiter const& d)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate_delimited(outit, g, d);
return result && !std::memcmp(generated.c_str(), expected, size);
}
///////////////////////////////////////////////////////////////////////////
template <typename Generator, typename Attribute, typename Delimiter>
inline bool
binary_test_delimited(char const *expected, std::size_t size,
Generator const& g, Attribute const &attr, Delimiter const& d)
{
namespace karma = boost::spirit::karma;
typedef std::basic_string<char> string_type;
// we don't care about the result of the "what" function.
// we only care that all generators have it:
karma::what(g);
string_type generated;
std::back_insert_iterator<string_type> outit(generated);
bool result = karma::generate_delimited(outit, g, d, attr);
return result && !std::memcmp(generated.c_str(), expected, size);
}
} // namespace spirit_test
#endif // !BOOST_SPIRIT_KARMA_TEST_FEB_23_2007_1221PM

View File

@@ -0,0 +1,109 @@
// Copyright (c) 2001-2010 Hartmut Kaiser
// Copyright (c) 2001-2010 Joel de Guzman
// Copyright (c) 2011 Aaron Graham
//
// 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)
#include <boost/spirit/repository/include/qi_advance.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_auxiliary.hpp>
#include <boost/spirit/include/qi_binary.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_directive.hpp>
#include <boost/spirit/include/qi_nonterminal.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_string.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/assign/std/list.hpp>
#include "test.hpp"
namespace spirit_test
{
template <typename Container, typename Parser>
bool test_c(Container const& in, Parser const& p, bool full_match = true)
{
// we don't care about the results of the "what" function.
// we only care that all parsers have it:
boost::spirit::qi::what(p);
typename Container::const_iterator first = in.begin();
typename Container::const_iterator const last = in.end();
return boost::spirit::qi::parse(first, last, p)
&& (!full_match || (first == last));
}
}
int main()
{
using spirit_test::test;
using spirit_test::test_c;
using namespace boost::spirit::qi::labels;
using boost::spirit::qi::locals;
using boost::spirit::qi::rule;
using boost::spirit::qi::uint_;
using boost::spirit::qi::byte_;
using namespace boost::assign;
using boost::spirit::repository::qi::advance;
{ // test basic functionality with random-access iterators
rule<char const*> start;
start = 'a' >> advance(3) >> "bc";
BOOST_TEST(test("a123bc", start));
start = (advance(3) | 'q') >> 'i';
BOOST_TEST(test("qi", start));
start = advance(-1);
BOOST_TEST(!test("0", start));
start = advance(-1) | "qi";
BOOST_TEST(test("qi", start));
start = advance(0) >> "abc" >> advance(10) >> "nopq" >> advance(0)
>> advance(8) >> 'z';
BOOST_TEST(test("abcdefghijklmnopqrstuvwxyz", start));
}
{ // test locals
rule<char const*, locals<unsigned> > start;
start = byte_ [_a = _1] >> advance(_a) >> "345";
BOOST_TEST(test("\x02""12345", start));
BOOST_TEST(!test("\x60""345", start));
}
{ // test basic functionality with bidirectional iterators
rule<std::list<char>::const_iterator, locals<int> > start;
std::list<char> list;
list.clear();
list += 1,2,'a','b','c';
start = byte_ [_a = _1] >> advance(_a) >> "abc";
BOOST_TEST(test_c(list, start));
list.clear();
list += 3,'q','i';
start = byte_ [_a = _1] >> advance(_a);
BOOST_TEST(!test_c(list, start));
start = byte_ [_a = _1] >> (advance(_a) | "qi");
BOOST_TEST(test_c(list, start));
list.clear();
list += 'a','b','c','d','e','f','g','h','i','j','k','l','m';
list += 'n','o','p','q','r','s','t','u','v','w','x','y','z';
start = advance(0) >> "abc" >> advance(10) >> "nopq" >> advance(0)
>> advance(8) >> 'z';
BOOST_TEST(test_c(list, start));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,145 @@
/*=============================================================================
Copyright (c) 2009 Chris Hoeppler
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)
=============================================================================*/
#include <boost/spirit/repository/include/qi_confix.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_auxiliary.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_directive.hpp>
#include <boost/spirit/include/qi_nonterminal.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_string.hpp>
#include <boost/phoenix/bind.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/object.hpp>
#include <boost/phoenix/operator.hpp>
#include <string>
#include "test.hpp"
namespace comment {
namespace spirit = boost::spirit;
namespace repo = boost::spirit::repository;
// Define a metafunction allowing to compute the type
// of the confix() construct
template <typename Prefix, typename Suffix = Prefix>
struct confix_spec_traits
{
typedef typename spirit::result_of::terminal<
repo::tag::confix(Prefix, Suffix)
>::type type;
};
template <typename Prefix, typename Suffix>
inline typename confix_spec_traits<Prefix, Suffix>::type
confix_spec(Prefix const& prefix, Suffix const& suffix)
{
return repo::confix(prefix, suffix);
}
inline confix_spec_traits<std::string>::type
confix_spec(const char* prefix, const char* suffix)
{
return repo::confix(std::string(prefix), std::string(suffix));
}
confix_spec_traits<std::string>::type const c_comment = confix_spec("/*", "*/");
confix_spec_traits<std::string>::type const cpp_comment = confix_spec("//", "\n");
}
int main()
{
using spirit_test::test_attr;
using spirit_test::test;
using namespace boost::spirit::ascii;
using namespace boost::spirit::qi::labels;
using boost::spirit::qi::locals;
using boost::spirit::qi::rule;
using boost::spirit::qi::debug;
namespace phx = boost::phoenix;
namespace repo = boost::spirit::repository;
{ // basic tests
rule<char const*> start;
start = repo::confix('a', 'c')['b'];
BOOST_TEST(test("abc", start));
start = repo::confix('a', 'c')['b'] | "abd";
BOOST_TEST(test("abd", start));
start = repo::confix("/*", "*/")[*(alpha - "*/")];
BOOST_TEST(test("/*aaaabababaaabbb*/", start));
start = repo::confix(char_('/') >> '*', '*' >> char_('/'))[*alpha - "*/"];
BOOST_TEST(test("/*aaaabababaaabba*/", start));
start = comment::c_comment[*(alpha - "*/")];
BOOST_TEST(test("/*aaaabababaaabbb*/", start));
// ignore the skipper!
BOOST_TEST(!test("/* aaaabababaaabba*/", start, space));
}
{ // basic tests w/ skipper
rule<char const*, space_type> start;
start = repo::confix('a', 'c')['b'];
BOOST_TEST(test(" a b c ", start, space));
start = repo::confix(char_('/') >> '*', '*' >> char_('/'))[*alpha - "*/"];
BOOST_TEST(test(" / *a b a b a b a a a b b b * / ", start, space));
}
{ // context tests
char ch;
rule<char const*, char()> a;
a = repo::confix("/*", "*/")[alpha][_val = _1];
BOOST_TEST(test("/*x*/", a[phx::ref(ch) = _1]));
BOOST_TEST(ch == 'x');
a %= repo::confix("/*", "*/")[alpha];
BOOST_TEST(test_attr("/*z*/", a, ch)); // attribute is given.
BOOST_TEST(ch == 'z');
}
{ // rules test
rule<char const*> a, b, c, start;
a = 'a';
b = 'b';
c = 'c';
a.name("a");
b.name("b");
c.name("c");
start.name("start");
debug(a);
debug(b);
debug(c);
debug(start);
start = repo::confix(a.alias(), c.alias())[b];
BOOST_TEST(test("abc", start));
}
{ // modifiers test
rule<char const*> start;
start = no_case[repo::confix("_A_", "_Z_")["heLLo"]];
BOOST_TEST(test("_a_hello_z_", start));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,98 @@
// Copyright (c) 2001-2010 Hartmut Kaiser
// Copyright (c) 2001-2010 Joel de Guzman
// Copyright (c) 2003 Vaclav Vesely
//
// 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)
#include <boost/spirit/repository/include/qi_distinct.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_string.hpp>
#include <boost/spirit/include/qi_nonterminal.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <iostream>
#include "test.hpp"
using namespace boost;
///////////////////////////////////////////////////////////////////////////////
namespace distinct
{
//[qi_distinct_encapsulation
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
namespace repo = boost::spirit::repository;
// Define metafunctions allowing to compute the type of the distinct()
// and ascii::char_() constructs
namespace traits
{
// Metafunction allowing to get the type of any repository::distinct(...)
// construct
template <typename Tail>
struct distinct_spec
: spirit::result_of::terminal<repo::tag::distinct(Tail)>
{};
// Metafunction allowing to get the type of any ascii::char_(...) construct
template <typename String>
struct char_spec
: spirit::result_of::terminal<spirit::tag::ascii::char_(String)>
{};
}
// Define a helper function allowing to create a distinct() construct from
// an arbitrary tail parser
template <typename Tail>
inline typename traits::distinct_spec<Tail>::type
distinct_spec(Tail const& tail)
{
return repo::distinct(tail);
}
// Define a helper function allowing to create a ascii::char_() construct
// from an arbitrary string representation
template <typename String>
inline typename traits::char_spec<String>::type
char_spec(String const& str)
{
return ascii::char_(str);
}
// the following constructs the type of a distinct_spec holding a
// charset("0-9a-zA-Z_") as its tail parser
typedef traits::char_spec<std::string>::type charset_tag_type;
typedef traits::distinct_spec<charset_tag_type>::type keyword_tag_type;
// Define a new Qi 'keyword' directive usable as a shortcut for a
// repository::distinct(char_(std::string("0-9a-zA-Z_")))
std::string const keyword_spec("0-9a-zA-Z_");
keyword_tag_type const keyword = distinct_spec(char_spec(keyword_spec));
//]
}
///////////////////////////////////////////////////////////////////////////////
int main()
{
using namespace spirit_test;
using namespace boost::spirit;
{
using namespace boost::spirit::ascii;
qi::rule<char const*, space_type> r;
r = distinct::keyword["description"] >> -lit(':') >> distinct::keyword["ident"];
BOOST_TEST(test("description ident", r, space));
BOOST_TEST(test("description:ident", r, space));
BOOST_TEST(test("description: ident", r, space));
BOOST_TEST(!test("descriptionident", r, space));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,265 @@
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2011 Thomas Bernard
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)
=============================================================================*/
#include <boost/spirit/repository/include/qi_keywords.hpp>
#include <boost/spirit/repository/include/qi_kwd.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_string.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/qi_directive.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_nonterminal.hpp>
#include <boost/spirit/include/support_argument.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/stl/container.hpp>
#include <vector>
#include <string>
#include <iostream>
#include "test.hpp"
struct x_attr
{
};
namespace boost { namespace spirit { namespace traits
{
template <>
struct container_value<x_attr>
{
typedef char type; // value type of container
};
template <>
struct push_back_container<x_attr, char>
{
static bool call(x_attr& /*c*/, char /*val*/)
{
// push back value type into container
return true;
}
};
}}}
int
main()
{
using spirit_test::test_attr;
using spirit_test::test;
using namespace boost::spirit;
using namespace boost::spirit::ascii;
using boost::spirit::repository::kwd;
using boost::spirit::repository::ikwd;
using boost::spirit::repository::dkwd;
using boost::spirit::qi::inf;
using boost::spirit::qi::omit;
using boost::spirit::qi::int_;
using boost::spirit::qi::lit;
using boost::spirit::qi::_1;
using boost::spirit::qi::lexeme;
{
// no constraints
boost::fusion::vector<char,char,int> data;
BOOST_TEST( test_attr("c=1 a=a", kwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], data, space));
BOOST_TEST( boost::fusion::at_c<0>(data) == 'a' );
BOOST_TEST( boost::fusion::at_c<1>(data) == 0 );
BOOST_TEST( boost::fusion::at_c<2>(data) == 1 );
BOOST_TEST( test("a=a c=1", kwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space));
BOOST_TEST( test("", kwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space));
// Exact
BOOST_TEST(test("a=a b=b c=1", kwd("a",1)[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space));
BOOST_TEST(test("a=a b=c b=e c=1", kwd("a",1)[ '=' > char_] / kwd("b",2)[ '=' > char_] / kwd("c")['=' > int_], space));
BOOST_TEST(!test("b=c b=e c=1", kwd("a",1)[ '=' > char_] / kwd("b",2)[ '=' > char_] / kwd("c")['=' > int_], space));
// Min - Max
BOOST_TEST(test("a=f b=c b=e c=1", kwd("a",1,2)[ '=' > char_] / kwd("b",0,2)[ '=' > char_] / kwd("c",1,2)['=' > int_], space));
BOOST_TEST(!test("b=c b=e c=1", kwd("a",1,2)[ '=' > char_] / kwd("b",0,1)[ '=' > char_] / kwd("c",1,2)['=' > int_], space));
BOOST_TEST(test("a=g a=f b=c b=e c=1", kwd("a",1,2)[ '=' > char_] / kwd("b",0,2)[ '=' > char_] / kwd("c",1,2)['=' > int_], space));
BOOST_TEST(!test("a=f a=e b=c b=e a=p c=1", kwd("a",1,2)[ '=' > char_] / kwd("b",0,1)[ '=' > char_] / kwd("c",1,2)['=' > int_], space));
// Min - inf
BOOST_TEST(test("a=f b=c b=e c=1", kwd("a",1,inf)[ '=' > char_] / kwd("b",0,inf)[ '=' > char_] / kwd("c",1,inf)['=' > int_], space ));
BOOST_TEST(!test("b=c b=e c=1", kwd("a",1,inf)[ '=' > char_] / kwd("b",0,inf)[ '=' > char_] / kwd("c",1,inf)['=' > int_], space ));
BOOST_TEST(test("a=f a=f a=g b=c b=e c=1 a=e", kwd("a",1,inf)[ '=' > char_] / kwd("b",0,inf)[ '=' > char_] / kwd("c",1,inf)['=' > int_], space ));
}
{ // Single keyword, empty string
BOOST_TEST(test(" ", kwd("aad")[char_],space));
// Single keyword
BOOST_TEST(test("aad E ", kwd("aad")[char_],space));
// Single no case keyword
BOOST_TEST(test("AaD E ", ikwd("aad")[char_],space));
}
{
// Vector container
boost::fusion::vector<std::vector<int>,std::vector<int>,std::vector<int> > data;
BOOST_TEST(test_attr(" a=1 b=2 b=5 c=3",kwd("a")[ '=' > int_] / kwd("b")[ '=' > int_] / kwd("c")['=' > int_] , data, space)
&& (boost::fusion::at_c<0>(data).size()==1)
&& (boost::fusion::at_c<0>(data)[0]==1)
&&(boost::fusion::at_c<1>(data).size()==2)
&&(boost::fusion::at_c<1>(data)[0]==2)
&&(boost::fusion::at_c<1>(data)[1]==5)
&&(boost::fusion::at_c<2>(data).size()==1)
&&(boost::fusion::at_c<2>(data)[0]==3)
);
}
{
// no_case test
BOOST_TEST( test("B=a c=1 a=E", no_case[kwd("a")[ "=E" ] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_]], space));
BOOST_TEST( test("B=a c=1 a=e", no_case[kwd("a")[ "=E" ] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_]], space));
BOOST_TEST( !test("B=a c=1 A=E", no_case[kwd("a")[ '=' > char_]] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space));
BOOST_TEST( test("b=a c=1 A=E", no_case[kwd("a")[ '=' > char_]] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space));
BOOST_TEST( !test("A=a c=1 a=E", kwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space));
BOOST_TEST( test("A=a c=1 a=E", ikwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space));
BOOST_TEST( !test("A=a C=1 a=E", ikwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space));
}
{
// iterator restoration
BOOST_TEST( test("a=a c=1 ba=d", (kwd("a")[ '=' > char_] / kwd("b")[ '=' > int_] / kwd("c")['=' > int_] ) > lit("ba=") > char_, space));
BOOST_TEST( test("A=a c=1 ba=d", (ikwd("a")[ '=' > char_] / kwd("b")[ '=' > int_] / kwd("c")['=' > int_] ) > lit("ba=") > char_, space));
}
{ // actions
namespace phx = boost::phoenix;
std::vector<int> v;
BOOST_TEST(test("b=2 c=4", kwd("b")['=' > int_][phx::ref(v)=_1] / kwd("c")[ '=' > int_ ],space) &&
v[0] == 2 );
}
{
// no constraints
boost::fusion::vector<char,char,int> data;
BOOST_TEST( test_attr("c,1,2=1 2,b=a", kwd( char_ >> lit(',') >> int_ )[ '=' >> char_] / kwd(int_ >> lit(',') >> char_)[ '=' >> char_] / kwd(char_ >> lit(',') >> int_ >> lit(',') >> int_)['=' >> int_], data, space));
BOOST_TEST( boost::fusion::at_c<0>(data) == 0 );
BOOST_TEST( boost::fusion::at_c<1>(data) == 'a');
BOOST_TEST( boost::fusion::at_c<2>(data) == 1 );
BOOST_TEST( test("2,b=a c,1,2=1", kwd( char_ >> ',' >> int_ )[ '=' >> char_] / kwd(int_ >> ',' >> char_)[ '=' >> char_] / kwd(char_ >> ',' >> int_ >> ',' >> int_)['=' >> int_], space));
BOOST_TEST( test("", kwd( char_ >> ',' >> int_ )[ '=' >> char_] / kwd(int_ >> ',' >> char_)[ '=' >> char_] / kwd(char_ >> ',' >> int_ >> ',' >> int_)['=' >> int_], space));
// Exact
BOOST_TEST(test("7a=a 5b=b 2c=1", kwd(int_ >> lit('a'),1)[ '=' >> char_] / kwd(int_ >> lit('b'))[ '=' >> char_] / kwd(int_ >> lit('c'))['=' >> int_], space));
BOOST_TEST(test("7a=a 3b=d 5b=b 2c=1", kwd(int_ >> lit('a'),1)[ '=' >> char_] / kwd(int_ >> lit('b'),2)[ '=' >> char_] / kwd(int_ >>'c')['=' >> int_], space));
BOOST_TEST(!test("7a=a 5b=b 2c=1", kwd(int_ >> lit('a'),1)[ '=' >> char_] / kwd(int_ >> lit('b'),2)[ '=' >> char_] / kwd(int_ >>'c')['=' >> int_], space));
// Min - Max
BOOST_TEST(test("6a=f 2b=c 3b=e 1c=1", kwd(int_ >> "a",1,2)[ '=' >> char_] / kwd(int_ >> "b",0,2)[ '=' >> char_] / kwd(int_ >> "c",1,2)['=' >> int_], space));
BOOST_TEST(!test("1b=c 6b=e 2c=1", kwd(int_ >> "a",1,2)[ '=' >> char_] / kwd(int_ >> "b",0,1)[ '=' >> char_] / kwd(int_ >> "c",1,2)['=' >> int_], space));
BOOST_TEST(test("4a=g 7a=f 2b=c 1b=e 4c=1", kwd(int_ >> "a",1,2)[ '=' >> char_] / kwd(int_ >> "b",0,2)[ '=' >> char_] / kwd(int_ >> "c",1,2)['=' >> int_], space));
BOOST_TEST(!test("1a=f a=e 2b=c 5b=e 6a=p 67c=1", kwd(int_ >> "a",1,2)[ '=' >> char_] / kwd(int_ >> "b",0,1)[ '=' >> char_] / kwd(int_ >> "c",1,2)['=' >> int_], space));
// Min - inf
BOOST_TEST(test("41a=f 44b=c 12b=e 45c=1", kwd(int_ >> "a",1,inf)[ '=' >> char_] / kwd(int_ >> "b",0,inf)[ '=' >> char_] / kwd(int_ >> "c",1,inf)['=' >> int_], space ));
BOOST_TEST(!test("31b=c 55b=e 2c=1", kwd("a",1,inf)[ '=' >> char_] / kwd("b",0,inf)[ '=' >> char_] / kwd("c",1,inf)['=' >> int_], space ));
BOOST_TEST(test("12a=f 45a=f 12a=g 1b=c 7b=e 12c=1 6a=e", kwd(int_ >> "a",1,inf)[ '=' >> char_] / kwd(int_ >> "b",0,inf)[ '=' >> char_] / kwd(int_ >> "c",1,inf)['=' >> int_], space ));
}
{
// Vector container
boost::fusion::vector<std::vector<int>,std::vector<int>,std::vector<int> > data;
BOOST_TEST(test_attr(" 41a=1 4b=2 12b=5 5c=3",kwd(int_ >> "a")[ '=' >> int_] / kwd(int_ >> "b")[ '=' >> int_] / kwd(int_ >> "c")['=' >> int_] , data, space)
&& (boost::fusion::at_c<0>(data).size()==1)
&& (boost::fusion::at_c<0>(data)[0]==1)
&&(boost::fusion::at_c<1>(data).size()==2)
&&(boost::fusion::at_c<1>(data)[0]==2)
&&(boost::fusion::at_c<1>(data)[1]==5)
&&(boost::fusion::at_c<2>(data).size()==1)
&&(boost::fusion::at_c<2>(data)[0]==3)
);
}
{
// no_case test
BOOST_TEST( test("12B=a 5c=1 1a=E", no_case[kwd(int_ >> "a")[ "=E" ] / kwd(int_ >> "b")[ '=' >> char_] / kwd(int_ >> "c")['=' >> int_]], space));
BOOST_TEST( test("5B=a 2c=1 5a=e", no_case[kwd(int_ >> "a")[ "=E" ] / kwd(int_ >> "b")[ '=' >> char_] / kwd(int_ >> "c")['=' >> int_]], space));
BOOST_TEST( !test("1B=a 8c=1 1A=E", no_case[kwd(int_ >> "a")[ '=' >> char_]] / kwd(int_ >> "b")[ '=' >> char_] / kwd(int_ >> "c")['=' >> int_], space));
BOOST_TEST( test("2b=a 6c=1 5A=E", no_case[kwd(int_ >> "a")[ '=' >> char_]] / kwd(int_ >> "b")[ '=' >> char_] / kwd(int_ >> "c")['=' >> int_], space));
BOOST_TEST( !test("1A=a 5c=1 1a=E", kwd(int_ >> "a")[ '=' >> char_] / kwd(int_ >> "b")[ '=' >> char_] / kwd(int_ >> "c")['=' >> int_], space));
BOOST_TEST( test("A=a 23c=1 a=E", ikwd("a")[ '=' >> char_] / kwd(int_ >> "b")[ '=' >> char_] / kwd(int_ >> "c")['=' >> int_], space));
BOOST_TEST( !test("A=a 21C=1 a=E", ikwd("a")[ '=' >> char_] / kwd(int_ >> "b")[ '=' >> char_] / kwd(int_ >> "c")['=' >> int_], space));
}
{
// iterator restoration
BOOST_TEST( test("4a=a c4=1 ba=d", (kwd(int_ >> "a")[ '=' >> char_] / kwd("b" >> int_)[ '=' >> int_] / kwd("c" >> int_ )['=' >> int_] ) >> lit("ba=") >> char_, space));
}
{ // actions
namespace phx = boost::phoenix;
std::vector<int> v;
BOOST_TEST(test("b4=2 c1=4", kwd("b" >> int_)['=' >> int_][phx::ref(v)=_1] / kwd("c" >> int_)[ '=' >> int_ ],space) &&
v[0] == 2 );
}
{
// complex keyword single test
int result=0;
BOOST_TEST( test_attr("(a,1) = 3214", kwd( '(' >> char_ >> ',' >> int_ >> ')' )['=' >> int_], result, space) );
BOOST_TEST(result==3214);
}
{
// Mixed complex keyword loop
boost::fusion::vector<int,int,int> data;
BOOST_TEST( test_attr("(a,1) = 3214 b += 2 hello 10 (a,2)=31", kwd( '(' >> char_ >> ',' >> int_ >> ')' )['=' >> int_] / kwd("hello")[int_] / kwd("b")["+=" >> int_], data, space) );
BOOST_TEST( boost::fusion::at_c<0>(data) == 31);
BOOST_TEST( boost::fusion::at_c<1>(data) == 10);
BOOST_TEST( boost::fusion::at_c<2>(data) == 2);
}
// dkwd and idkwd
{
BOOST_TEST( test("a =a", dkwd("a")[ '=' > char_] , space));
BOOST_TEST( !test("a=a", dkwd("a")[ '=' > char_] , space));
BOOST_TEST(test("a =a b =b c=1", dkwd("a",1)[ '=' > char_] / dkwd("b",1,2)[ '=' > char_] / kwd("c")['=' > int_], space));
BOOST_TEST(!test("a=a b=b c =1", dkwd("a",1)[ '=' > char_] / dkwd("b",1,2)[ '=' > char_] / kwd("c")['=' > int_], space));
BOOST_TEST(test("a =a b =b b =d c=1", dkwd("a",1,inf)[ '=' > char_] / dkwd("b",2,inf)[ '=' > char_] / kwd("c")['=' > int_], space));
}
{ // attribute customization
// x_attr x;
// test_attr("a = b c = d", kwd("a")['=' > char_] / kwd("c")['=' > char_], x);
}
return boost::report_errors();
}

View File

@@ -0,0 +1,98 @@
/*=============================================================================
Copyright (c) 2011 Jamboree
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)
=============================================================================*/
#include <boost/spirit/repository/include/qi_seek.hpp>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_string.hpp>
#include <boost/spirit/include/qi_int.hpp>
#include <boost/spirit/include/qi_sequence.hpp>
#include <boost/spirit/include/qi_plus.hpp>
#include <boost/spirit/include/qi_eoi.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <vector>
#include "test.hpp"
///////////////////////////////////////////////////////////////////////////////
int main()
{
using namespace spirit_test;
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
using boost::spirit::repository::qi::seek;
using boost::spirit::standard::space;
// test eoi
{
using qi::eoi;
BOOST_TEST(test("", seek[eoi]));
BOOST_TEST(test(" ", seek[eoi], space));
BOOST_TEST(test("a", seek[eoi]));
BOOST_TEST(test(" a", seek[eoi], space));
}
// test literal finding
{
using qi::int_;
using qi::char_;
int i = 0;
BOOST_TEST(
test_attr("!@#$%^&*KEY:123", seek["KEY:"] >> int_, i)
&& i == 123
);
}
// test sequence finding
{
using qi::int_;
using qi::lit;
int i = 0;
BOOST_TEST(
test_attr("!@#$%^&* KEY : 123", seek[lit("KEY") >> ':'] >> int_, i, space)
&& i == 123
);
}
// test attr finding
{
using qi::int_;
std::vector<int> v;
BOOST_TEST( // expect partial match
test_attr("a06b78c3d", +seek[int_], v, false)
&& v[0] == 6 && v[1] == 78 && v[2] == 3
);
}
// test action
{
using phx::ref;
bool b = false;
BOOST_TEST( // expect partial match
test("abcdefg", seek["def"][ref(b) = true], false)
&& b
);
}
// past the end regression GH#658
BOOST_TEST(!test(" ", seek['x'], space));
return boost::report_errors();
}

View File

@@ -0,0 +1,396 @@
/*=============================================================================
Copyright (c) 2001-2010 Joel de Guzman
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)
=============================================================================*/
#include <boost/spirit/repository/include/qi_subrule.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_string.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/qi_auxiliary.hpp>
#include <boost/spirit/include/qi_nonterminal.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/object.hpp>
#include <boost/phoenix/bind.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <string>
#include <cstring>
#include <iostream>
#include "test.hpp"
int
main()
{
using spirit_test::test_attr;
using spirit_test::test;
using namespace boost::spirit::ascii;
using namespace boost::spirit::qi::labels;
using boost::spirit::qi::locals;
using boost::spirit::qi::rule;
using boost::spirit::qi::int_;
using boost::spirit::qi::fail;
using boost::spirit::qi::on_error;
using boost::spirit::qi::debug;
using boost::spirit::repository::qi::subrule;
namespace phx = boost::phoenix;
{ // basic tests
subrule<99> entry;
subrule<42> a;
subrule<48> b;
subrule<16> c;
rule<char const*> start;
entry.name("entry");
a.name("a");
b.name("b");
c.name("c");
start.name("start");
// debug(entry);
// debug(a);
// debug(b);
// debug(c);
debug(start);
// subrules with no rule
BOOST_TEST(test("abcabcacb", (
entry = *(a | b | c)
, a = 'a'
, b = 'b'
, c = 'c'
)));
// check subrule group behaves as a parser
BOOST_TEST(test("xabcabcacb", 'x' >> (
entry = *(a | b | c)
, a = 'a'
, b = 'b'
, c = 'c'
)));
// subrules in a rule
start = (
entry = *(a | b | c)
, a = 'a'
, b = 'b'
, c = 'c'
);
BOOST_TEST(test("abcabcacb", start));
// subrule -> rule call
start = (
entry = (a | b) >> (start | b)
, a = 'a'
, b = 'b'
);
BOOST_TEST(test("aaaabababaaabbb", start));
BOOST_TEST(test("aaaabababaaabba", start, false));
// subrule recursion
start = (
entry = (a | b) >> (entry | b)
, a = 'a'
, b = 'b'
);
BOOST_TEST(test("aaaabababaaabbb", start));
BOOST_TEST(test("aaaabababaaabba", start, false));
// no-ops
#if defined(BOOST_CLANG) && defined(__has_warning)
# pragma clang diagnostic push
# if __has_warning("-Wself-assign-overloaded")
# pragma clang diagnostic ignored "-Wself-assign-overloaded"
# endif
#endif
a = a;
#if defined(BOOST_CLANG) && defined(__has_warning)
# pragma clang diagnostic pop
#endif
subrule<42> aa(a);
}
{ // basic tests w/ skipper, subrules declared const
subrule<0> const entry("entry");
subrule<1> const a("a");
subrule<2> const b("b");
subrule<3> const c("c");
rule<char const*, space_type> start("start");
// debug(entry);
// debug(a);
// debug(b);
// debug(c);
debug(start);
start = (
entry = *(a | b | c)
, a = 'a'
, b = 'b'
, c = 'c'
);
BOOST_TEST(test(" a b c a b c a c b ", start, space));
start = (
entry = (a | b) >> (entry | b)
, a = 'a'
, b = 'b'
);
BOOST_TEST(test(" a a a a b a b a b a a a b b b ", start, space));
BOOST_TEST(test(" a a a a b a b a b a a a b b a ", start, space, false));
// no-ops
#if defined(BOOST_CLANG) && defined(__has_warning)
# pragma clang diagnostic push
# if __has_warning("-Wself-assign-overloaded")
# pragma clang diagnostic ignored "-Wself-assign-overloaded"
# endif
#endif
a = a;
#if defined(BOOST_CLANG) && defined(__has_warning)
# pragma clang diagnostic pop
#endif
subrule<1> aa(a);
}
{ // context tests
char ch;
rule<char const*, char()> a;
subrule<0, char()> entry;
a = (entry = alpha[_val = _1])[_val = _1];
BOOST_TEST(test("x", a[phx::ref(ch) = _1]));
BOOST_TEST(ch == 'x');
a %= (entry = alpha[_val = _1]);
BOOST_TEST(test_attr("z", a, ch)); // attribute is given.
BOOST_TEST(ch == 'z');
}
{ // auto subrules tests
char ch;
rule<char const*, char()> a;
subrule<0, char()> entry;
a = (entry %= alpha)[_val = _1];
BOOST_TEST(test("x", a[phx::ref(ch) = _1]));
BOOST_TEST(ch == 'x');
a %= (entry %= alpha);
BOOST_TEST(test_attr("z", a, ch)); // attribute is given.
BOOST_TEST(ch == 'z');
}
{ // auto subrules tests: allow stl containers as attributes to
// sequences (in cases where attributes of the elements
// are convertible to the value_type of the container or if
// the element itself is an stl container with value_type
// that is convertible to the value_type of the attribute).
std::string s;
rule<char const*, std::string()> r;
subrule<0, std::string()> entry;
r %= (entry %= char_ >> *(',' >> char_));
BOOST_TEST(test("a,b,c,d,e,f", r[phx::ref(s) = _1]));
BOOST_TEST(s == "abcdef");
BOOST_TEST(test("abcdef", (
entry %= char_ >> char_ >> char_ >> char_ >> char_ >> char_
)[phx::ref(s) = _1]));
BOOST_TEST(s == "abcdef");
}
{ // synth attribute value-init
std::string s;
subrule<0, char()> sr;
BOOST_TEST(test_attr("abcdef", +(sr = alpha[_val += _1]), s));
BOOST_TEST(s == "abcdef");
}
{ // auto subrules aliasing tests
char ch;
rule<char const*, char()> r;
subrule<0, char()> a;
subrule<1, char()> b;
r %= (
a %= b
, b %= alpha
);
BOOST_TEST(test("x", r[phx::ref(ch) = _1]));
BOOST_TEST(ch == 'x');
BOOST_TEST(test_attr("z", r, ch)); // attribute is given.
BOOST_TEST(ch == 'z');
}
{ // context (w/arg) tests
char ch;
// entry subrule with 1 arg
rule<char const*, char(int)> a;
subrule<1, char(int)> sr1;
a %= (
sr1 = alpha[_val = _1 + _r1]
)(_r1);
BOOST_TEST(test("x", a(phx::val(1))[phx::ref(ch) = _1]));
BOOST_TEST(ch == 'x' + 1);
// other subrule with 1 arg
subrule<0, char()> sr0;
a %= (
sr0 %= sr1(1)
, sr1 = alpha[_val = _1 + _r1]
);
// allow scalars as subrule args too
rule<char const*, char()> b;
b %= (
sr1 = alpha[_val = _1 + _r1]
)(1);
BOOST_TEST(test_attr("b", b, ch));
BOOST_TEST(ch == 'b' + 1);
// entry subrule with 2 args
subrule<2, char(int, int)> sr2;
BOOST_TEST(test_attr("a", (
sr2 = alpha[_val = _1 + _r1 + _r2]
)(1, 2), ch));
BOOST_TEST(ch == 'a' + 1 + 2);
// multiple subrules + args
BOOST_TEST(test_attr("ba", (
sr2 = alpha[_val = _1 + _r1 + _r2] >> sr1(3)[_val -= _1]
, sr1 = alpha[_val = _1 + _r1]
)(1, 2), ch));
BOOST_TEST(ch == ('b' + 1 + 2) - ('a' + 3));
}
{ // context (w/ reference arg) tests
char ch;
subrule<0, void(char&)> sr; // 1 arg (reference) - direct
BOOST_TEST(test("x", (sr = alpha[_r1 = _1])(phx::ref(ch))));
BOOST_TEST(ch == 'x');
rule<char const*, void(char&)> a; // forwarded via a rule
a = (sr = alpha[_r1 = _1])(_r1);
BOOST_TEST(test("y", a(phx::ref(ch))));
BOOST_TEST(ch == 'y');
}
{ // context (w/locals) tests
rule<char const*> r;
subrule<0, locals<char> > a; // 1 local
r = (
a = alpha[_a = _1] >> char_(_a)
);
BOOST_TEST(test("aa", r));
BOOST_TEST(!test("ax", r));
}
{ // context (w/args and locals) tests
rule<char const*, void(int)> a;
subrule<0, void(int), locals<char> > sr; // 1 arg + 1 local
a = (
sr = alpha[_a = _1 + _r1] >> char_(_a)
)(_r1);
BOOST_TEST(test("ab", a(phx::val(1))));
BOOST_TEST(test("xy", a(phx::val(1))));
BOOST_TEST(!test("ax", a(phx::val(1))));
}
{ // void() has unused type (void == unused_type)
std::pair<int, char> attr;
subrule<0, void()> sr;
BOOST_TEST(test_attr("123ax", int_ >> char_ >> (sr = char_), attr));
BOOST_TEST(attr.first == 123);
BOOST_TEST(attr.second == 'a');
}
{ // test that injected attributes are ok
rule<char const*> r;
subrule<0, char(int)> sr;
r = (
sr = char_(_r1)[_val = _1]
)(42);
}
{ // show that sra = srb and sra %= srb works as expected
subrule<0, int()> sra;
subrule<1, int()> srb;
int attr;
BOOST_TEST(test_attr("123", (sra %= int_), attr));
BOOST_TEST(attr == 123);
BOOST_TEST(test_attr("123", (srb %= sra, sra %= int_), attr));
BOOST_TEST(attr == 123);
BOOST_TEST(test_attr("123", (srb = sra, sra %= int_), attr));
BOOST_TEST(attr == 123);
}
{ // std::string as container attribute with auto subrules
subrule<0, std::string()> text;
std::string attr;
BOOST_TEST(test_attr("x", (
text %= +(!char_(')') >> !char_('>') >> char_)
), attr));
BOOST_TEST(attr == "x");
}
// { // error handling
//
// using namespace boost::spirit::ascii;
// using boost::phoenix::construct;
// using boost::phoenix::bind;
//
// rule<char const*> r;
// r = '(' > int_ > ',' > int_ > ')';
//
// on_error<fail>
// (
// r, std::cout
// << phx::val("Error! Expecting: ")
// << _4
// << phx::val(", got: \"")
// << construct<std::string>(_3, _2)
// << phx::val("\"")
// << std::endl
// );
//
// BOOST_TEST(test("(123,456)", r));
// BOOST_TEST(!test("(abc,def)", r));
// BOOST_TEST(!test("(123,456]", r));
// BOOST_TEST(!test("(123;456)", r));
// BOOST_TEST(!test("[123,456]", r));
// }
return boost::report_errors();
}

View File

@@ -0,0 +1,104 @@
/*=============================================================================
Copyright (c) 2001-2010 Joel de Guzman
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)
=============================================================================*/
#if !defined(BOOST_SPIRIT_TEST_FEBRUARY_01_2007_0605PM)
#define BOOST_SPIRIT_TEST_FEBRUARY_01_2007_0605PM
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/qi_what.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <iostream>
namespace spirit_test
{
template <typename Char, typename Parser>
inline bool test(Char const* in, Parser const& p, bool full_match = true)
{
// we don't care about the result of the "what" function.
// we only care that all parsers have it:
boost::spirit::qi::what(p);
Char const* last = in;
while (*last)
last++;
return boost::spirit::qi::parse(in, last, p)
&& (!full_match || (in == last));
}
template <typename Char, typename Parser, typename Skipper>
inline bool test(Char const* in, Parser const& p
, Skipper const& s, bool full_match = true)
{
// we don't care about the result of the "what" function.
// we only care that all parsers have it:
boost::spirit::qi::what(p);
Char const* last = in;
while (*last)
last++;
return boost::spirit::qi::phrase_parse(in, last, p, s)
&& (!full_match || (in == last));
}
template <typename Char, typename Parser, typename Attr>
inline bool test_attr(Char const* in, Parser const& p
, Attr& attr, bool full_match = true)
{
// we don't care about the result of the "what" function.
// we only care that all parsers have it:
boost::spirit::qi::what(p);
Char const* last = in;
while (*last)
last++;
return boost::spirit::qi::parse(in, last, p, attr)
&& (!full_match || (in == last));
}
template <typename Char, typename Parser, typename Attr, typename Skipper>
inline bool test_attr(Char const* in, Parser const& p
, Attr& attr, Skipper const& s, bool full_match = true)
{
// we don't care about the result of the "what" function.
// we only care that all parsers have it:
boost::spirit::qi::what(p);
Char const* last = in;
while (*last)
last++;
return boost::spirit::qi::phrase_parse(in, last, p, s, attr)
&& (!full_match || (in == last));
}
struct printer
{
typedef boost::spirit::utf8_string string;
void element(string const& tag, string const& value, int depth) const
{
for (int i = 0; i < (depth*4); ++i) // indent to depth
std::cout << ' ';
std::cout << "tag: " << tag;
if (value != "")
std::cout << ", value: " << value;
std::cout << std::endl;
}
};
inline void print_info(boost::spirit::info const& what)
{
using boost::spirit::basic_info_walker;
printer pr;
basic_info_walker<printer> walker(pr, what.tag, 0);
boost::apply_visitor(walker, what.value);
}
}
#endif

View File

@@ -0,0 +1,81 @@
# Jamfile
#
# Copyright (c) 2007-2008 Steven Watanabe
# Copyright (c) 2009 Joel de Guzman
# Copyright (c) 2009 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
import testing ;
import path ;
import regex ;
import print ;
import sequence ;
import feature ;
project boost/spirit/repository/test/test_headers
: requirements
<include>$(BOOST_ROOT)
<include>../../../../..
<c++-template-depth>300
;
headers =
[
path.glob-tree ../../../../../boost/spirit/repository/include : *.hpp
] ;
main_headers =
[
path.glob-tree ../../../../../boost/spirit/include : *.hpp : classic* phoenix1*
] ;
for local file in $(headers)
{
compile test.cpp
: # requirements
<define>BOOST_SPIRIT_HEADER_NAME=$(file)
<dependency>$(file)
: # test name
[ regex.replace [ path.relative-to ../../../../../boost/spirit/repository $(file) ] "/" "_" ]
;
}
feature.feature <generate-include-all-order> : forward reverse : incidental ;
rule generate-include-all ( target : sources * : properties * )
{
print.output $(target) ;
if <generate-include-all-order>reverse in $(properties)
{
sources = [ sequence.reverse $(sources) ] ;
}
for local file in $(sources)
{
print.text "#include <$(file:G=)>
" : overwrite ;
}
}
make auto_all1.cpp
: $(headers) $(main_headers)
: @generate-include-all
;
make auto_all2.cpp
: $(headers) $(main_headers)
: @generate-include-all
: <generate-include-all-order>reverse
;
# this ought to catch non-inlined functions and other duplicate definitions
link auto_all1.cpp auto_all2.cpp main.cpp
: <include>.
: auto_all_headers
;

View File

@@ -0,0 +1,14 @@
// Copyright (c) 2003-2008 Matthias Christian Schabel
// Copyright (c) 2007-2008 Steven Watanabe
// Copyright (c) 2010 Joel de Guzman
// Copyright (c) 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)
int main()
{
return 0;
}

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2003-2008 Matthias Christian Schabel
// Copyright (c) 2007-2008 Steven Watanabe
// Copyright (c) 2010 Joel de Guzman
// Copyright (c) 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)
#define BOOST_SPIRIT_STRINGIZE_IMPL(x) #x
#define BOOST_SPIRIT_STRINGIZE(x) BOOST_SPIRIT_STRINGIZE_IMPL(x)
#define BOOST_SPIRIT_HEADER BOOST_SPIRIT_STRINGIZE(BOOST_SPIRIT_HEADER_NAME)
#include BOOST_SPIRIT_HEADER
#include BOOST_SPIRIT_HEADER
int main()
{
return 0;
}