| Home | Libraries | People | FAQ | More

##### 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

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.