Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext
Handling Alternation and Recursion

Most grammars are a little more complicated than the one in the preceding section. For the sake of illustration, let's define a rather nonsensical grammar that matches any expression and recurses to the leftmost terminal and returns its value. It will demonstrate how two key concepts of Proto grammars -- alternation and recursion -- interact with transforms. The grammar is described below.

// A grammar that matches any expression, and a function object
// that returns the value of the leftmost terminal.
struct LeftmostLeaf
  : proto::or_<
        // If the expression is a terminal, return its value
        proto::when<
            proto::terminal< _ >
          , proto::_value
        >
        // Otherwise, it is a non-terminal. Return the result
        // of invoking LeftmostLeaf on the 0th (leftmost) child.
      , proto::when<
            _
          , LeftmostLeaf( proto::_child0 )
        >
    >
{};

// A Proto terminal wrapping std::cout
proto::terminal< std::ostream & >::type cout_ = { std::cout };

// Create an expression and use LeftmostLeaf to extract the
// value of the leftmost terminal, which will be std::cout.
std::ostream & sout = LeftmostLeaf()( cout_ << "the answer: " << 42 << '\n' );

We've seen proto::or_<> before. Here it is serving two roles. First, it is a grammar that matches any of its alternate sub-grammars; in this case, either a terminal or a non-terminal. Second, it is also a function object that accepts an expression, finds the alternate sub-grammar that matches the expression, and applies its transform. And since LeftmostLeaf inherits from proto::or_<>, LeftmostLeaf is also both a grammar and a function object.

[Note] Note

The second alternate uses proto::_ as its grammar. Recall that proto::_ is the wildcard grammar that matches any expression. Since alternates in proto::or_<> are tried in order, and since the first alternate handles all terminals, the second alternate handles all (and only) non-terminals. Often enough, proto::when< _, some-transform > is the last alternate in a grammar, so for improved readability, you could use the equivalent proto::otherwise< some-transform >.

The next section describes this grammar further.


PrevUpHomeNext