373 lines
9.2 KiB
Plaintext
373 lines
9.2 KiB
Plaintext
[/==============================================================================
|
|
Copyright (C) 2001-2010 Joel de Guzman
|
|
Copyright (C) 2001-2005 Dan Marsden
|
|
Copyright (C) 2001-2010 Thomas Heller
|
|
|
|
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 Statement]
|
|
|
|
[*/Lazy statements.../]
|
|
|
|
The expressions presented so far are sufficiently
|
|
powerful to construct quite elaborate structures. We have presented lazy-functions
|
|
and lazy-operators. How about lazy-statements? First, an appetizer:
|
|
|
|
Print all odd-numbered contents of an STL container using `std::for_each`
|
|
([@../../example/all_odds.cpp all_odds.cpp]):
|
|
|
|
std::for_each(c.begin(), c.end(),
|
|
if_(arg1 % 2 == 1)
|
|
[
|
|
cout << arg1 << ' '
|
|
]
|
|
);
|
|
|
|
Huh? Is that valid C++? Read on...
|
|
|
|
Yes, it is valid C++. The sample code above is as close as you can get to the
|
|
syntax of C++. This stylized C++ syntax differs from actual C++ code. First, the
|
|
`if` has a trailing underscore. Second, the block uses square brackets instead
|
|
of the familiar curly braces {}.
|
|
|
|
[note *C++ in C++?*
|
|
|
|
In as much as __spirit__ attempts to mimic EBNF in C++,
|
|
Phoenix attempts to mimic C++ in C++!!!
|
|
]
|
|
|
|
[note Unlike lazy functions and lazy operators, lazy statements always
|
|
return void.]
|
|
|
|
Here are more examples with annotations. The code almost speaks for itself.
|
|
|
|
[section Block Statement]
|
|
|
|
[/ #include <boost/phoenix/statement/sequence.hpp>]
|
|
|
|
Syntax:
|
|
|
|
statement,
|
|
statement,
|
|
....
|
|
statement
|
|
|
|
Basically, these are comma separated statements. Take note that unlike the C/C++
|
|
semicolon, the comma is a separator put *in-between* statements. This is like
|
|
Pascal's semicolon separator, rather than C/C++'s semicolon terminator. For
|
|
example:
|
|
|
|
statement,
|
|
statement,
|
|
statement, // ERROR!
|
|
|
|
Is an error. The last statement should not have a comma. Block statements can be
|
|
grouped using the parentheses. Again, the last statement in a group should not
|
|
have a trailing comma.
|
|
|
|
statement,
|
|
statement,
|
|
(
|
|
statement,
|
|
statement
|
|
),
|
|
statement
|
|
|
|
Outside the square brackets, block statements should be grouped. For example:
|
|
|
|
std::for_each(c.begin(), c.end(),
|
|
(
|
|
do_this(arg1),
|
|
do_that(arg1)
|
|
)
|
|
);
|
|
|
|
Wrapping a comma operator chain around a parentheses pair blocks the
|
|
interpretation as an argument separator. The reason for the exception for
|
|
the square bracket operator is that the operator always takes exactly one
|
|
argument, so it "transforms" any attempt at multiple arguments with a comma
|
|
operator chain (and spits out an error for zero arguments).
|
|
|
|
[endsect]
|
|
|
|
[section if_ Statement]
|
|
|
|
#include <boost/phoenix/statement/if.hpp>
|
|
|
|
We have seen the `if_` statement. The syntax is:
|
|
|
|
if_(conditional_expression)
|
|
[
|
|
sequenced_statements
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section '''if_else_''' Statement]
|
|
|
|
#include <boost/phoenix/statement/if.hpp>
|
|
|
|
The syntax is
|
|
|
|
if_(conditional_expression)
|
|
[
|
|
sequenced_statements
|
|
]
|
|
.else_
|
|
[
|
|
sequenced_statements
|
|
]
|
|
|
|
Take note that `else` has a leading dot and a trailing underscore: `.else_`
|
|
|
|
Example: This code prints out all the elements and appends `" > 5"`, `" == 5"`
|
|
or `" < 5"` depending on the element's actual value:
|
|
|
|
std::for_each(c.begin(), c.end(),
|
|
if_(arg1 > 5)
|
|
[
|
|
cout << arg1 << " > 5\n"
|
|
]
|
|
.else_
|
|
[
|
|
if_(arg1 == 5)
|
|
[
|
|
cout << arg1 << " == 5\n"
|
|
]
|
|
.else_
|
|
[
|
|
cout << arg1 << " < 5\n"
|
|
]
|
|
]
|
|
);
|
|
|
|
Notice how the `if_else_` statement is nested.
|
|
|
|
[/note `if_` is one example of a customized actor. See [link phoenix.advanced.extending.extending_actors Extending Actors] for more details]
|
|
|
|
[endsect]
|
|
|
|
[section switch_ Statement]
|
|
|
|
#include <boost/phoenix/statement/switch.hpp>
|
|
|
|
The syntax is:
|
|
|
|
switch_(integral_expression)
|
|
[
|
|
case_<integral_value>(sequenced_statements),
|
|
...
|
|
default_(sequenced_statements)
|
|
]
|
|
|
|
A comma separated list of cases, and an optional default can be provided. Note unlike
|
|
a normal switch statement, cases do not fall through.
|
|
|
|
Example: This code prints out `"one"`, `"two"` or `"other value"` depending on the
|
|
element's actual value:
|
|
|
|
std::for_each(c.begin(), c.end(),
|
|
switch_(arg1)
|
|
[
|
|
case_<1>(std::cout << val("one") << '\n'),
|
|
case_<2>(std::cout << val("two") << '\n'),
|
|
default_(std::cout << val("other value") << '\n')
|
|
]
|
|
);
|
|
|
|
[endsect]
|
|
|
|
[section while_ Statement]
|
|
|
|
#include <boost/phoenix/statement/while.hpp>
|
|
|
|
The syntax is:
|
|
|
|
while_(conditional_expression)
|
|
[
|
|
sequenced_statements
|
|
]
|
|
|
|
Example: This code decrements each element until it reaches zero and prints out
|
|
the number at each step. A newline terminates the printout of each value.
|
|
|
|
std::for_each(c.begin(), c.end(),
|
|
(
|
|
while_(arg1--)
|
|
[
|
|
cout << arg1 << ", "
|
|
],
|
|
cout << val("\n")
|
|
)
|
|
);
|
|
|
|
[endsect]
|
|
|
|
[section '''do_while_''' Statement]
|
|
|
|
#include <boost/phoenix/statement/do_while.hpp>
|
|
|
|
The syntax is:
|
|
|
|
do_
|
|
[
|
|
sequenced_statements
|
|
]
|
|
.while_(conditional_expression)
|
|
|
|
Again, take note that `while` has a leading dot and a trailing underscore:
|
|
`.while_`
|
|
|
|
Example: This code is almost the same as the previous example above with a
|
|
slight twist in logic.
|
|
|
|
std::for_each(c.begin(), c.end(),
|
|
(
|
|
do_
|
|
[
|
|
cout << arg1 << ", "
|
|
]
|
|
.while_(arg1--),
|
|
cout << val("\n")
|
|
)
|
|
);
|
|
|
|
[/note `do_` is one example of a customized actor. See [link phoenix.advanced.extending.extending_actors Extending Actors] for more details]
|
|
|
|
[endsect]
|
|
|
|
[section:for_statement for_ Statement]
|
|
|
|
#include <boost/phoenix/statement/for.hpp>
|
|
|
|
The syntax is:
|
|
|
|
for_(init_statement, conditional_expression, step_statement)
|
|
[
|
|
sequenced_statements
|
|
]
|
|
|
|
It is again very similar to the C++ for statement. Take note that the
|
|
init_statement, conditional_expression and '''step_statement''' are separated by the
|
|
comma instead of the semi-colon and each must be present (i.e. `for_(,,)` is
|
|
invalid). This is a case where the [link phoenix.modules.core.nothing `nothing`]
|
|
actor can be useful.
|
|
|
|
Example: This code prints each element N times where N is the element's value. A
|
|
newline terminates the printout of each value.
|
|
|
|
int iii;
|
|
std::for_each(c.begin(), c.end(),
|
|
(
|
|
for_(ref(iii) = 0, ref(iii) < arg1, ++ref(iii))
|
|
[
|
|
cout << arg1 << ", "
|
|
],
|
|
cout << val("\n")
|
|
)
|
|
);
|
|
|
|
As before, all these are lazily evaluated. The result of such statements are in
|
|
fact expressions that are passed on to STL's for_each function. In the viewpoint
|
|
of `for_each`, what was passed is just a functor, no more, no less.
|
|
|
|
[endsect]
|
|
|
|
[section try_ catch_ Statement]
|
|
|
|
#include <boost/phoenix/statement/try_catch.hpp>
|
|
|
|
The syntax is:
|
|
|
|
try_
|
|
[
|
|
sequenced_statements
|
|
]
|
|
.catch_<exception_type>()
|
|
[
|
|
sequenced_statements
|
|
]
|
|
.catch_<another_exception_type>(local-id)
|
|
[
|
|
sequenced_statements
|
|
]
|
|
...
|
|
.catch_all
|
|
[
|
|
sequenced_statement
|
|
]
|
|
|
|
Note the usual underscore after try and catch, and the extra parentheses required
|
|
after the catch.
|
|
|
|
The second form of catch statement can refer thrown exception using specified
|
|
local-id, which is __phoenix_local_variable__, in sequenced_statements.
|
|
|
|
[/note `do_` is one example of a customized actor. See [link phoenix.advanced.extending.extending_actors Extending Actors] for more details]
|
|
|
|
Example: The following code calls the (lazy) function `f` for each element, and
|
|
prints messages about different exception types it catches.
|
|
|
|
try_
|
|
[
|
|
f(arg1)
|
|
]
|
|
.catch_<runtime_error>()
|
|
[
|
|
cout << val("caught runtime error or derived\n")
|
|
]
|
|
.catch_<exception>(e_)
|
|
[
|
|
cout << val("caught exception or derived: ") << bind(&exception::what, e_) << val("\n")
|
|
]
|
|
.catch_all
|
|
[
|
|
cout << val("caught some other type of exception\n")
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section throw_]
|
|
|
|
#include <boost/phoenix/statement/throw.hpp>
|
|
|
|
As a natural companion to the try/catch support, the statement module provides
|
|
lazy throwing and re-throwing of exceptions.
|
|
|
|
The syntax to throw an exception is:
|
|
|
|
throw_(exception_expression)
|
|
|
|
The syntax to re-throw an exception is:
|
|
|
|
throw_()
|
|
|
|
Example: This code extends the try/catch example, re-throwing exceptions derived from
|
|
runtime_error or exception, and translating other exception types to runtime_errors.
|
|
|
|
try_
|
|
[
|
|
f(arg1)
|
|
]
|
|
.catch_<runtime_error>()
|
|
[
|
|
cout << val("caught runtime error or derived\n"),
|
|
throw_()
|
|
]
|
|
.catch_<exception>()
|
|
[
|
|
cout << val("caught exception or derived\n"),
|
|
throw_()
|
|
]
|
|
.catch_all
|
|
[
|
|
cout << val("caught some other type of exception\n"),
|
|
throw_(runtime_error("translated exception"))
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|