Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext
Fuzzy and Exact Matches of Terminals

The terminals in an expression tree could be const or non-const references, or they might not be references at all. When writing grammars, you usually don't have to worry about it because proto::matches<> gives you a little wiggle room when matching terminals. A grammar such as proto::terminal<int> will match a terminal of type int, int &, or int const &.

You can explicitly specify that you want to match a reference type. If you do, the type must match exactly. For instance, a grammar such as proto::terminal<int &> will only match an int &. It will not match an int or an int const &.

The table below shows how Proto matches terminals. The simple rule is: if you want to match only reference types, you must specify the reference in your grammar. Otherwise, leave it off and Proto will ignore const and references.

Table 1.7. proto::matches<> and Reference / CV-Qualification of Terminals

Terminal

Grammar

Matches?

T

T

yes

T &

T

yes

T const &

T

yes

T

T &

no

T &

T &

yes

T const &

T &

no

T

T const &

no

T &

T const &

no

T const &

T const &

yes


This begs the question: What if you want to match an int, but not an int & or an int const &? For forcing exact matches, Proto provides the proto::exact<> template. For instance, proto::terminal< proto::exact<int> > would only match an int held by value.

Proto gives you extra wiggle room when matching array types. Array types match themselves or the pointer types they decay to. This is especially useful with character arrays. The type returned by proto::as_expr("hello") is proto::terminal<char const[6]>::type. That's a terminal containing a 6-element character array. Naturally, you can match this terminal with the grammar proto::terminal<char const[6]>, but the grammar proto::terminal<char const *> will match it as well, as the following code fragment illustrates.

struct CharString
  : proto::terminal< char const * >
{};

typedef proto::terminal< char const[6] >::type char_array;

BOOST_MPL_ASSERT(( proto::matches< char_array, CharString > ));

What if we only wanted CharString to match terminals of exactly the type char const *? You can use proto::exact<> here to turn off the fuzzy matching of terminals, as follows:

struct CharString
  : proto::terminal< proto::exact< char const * > >
{};

typedef proto::terminal<char const[6]>::type char_array;
typedef proto::terminal<char const *>::type  char_string;

BOOST_MPL_ASSERT(( proto::matches< char_string, CharString > ));
BOOST_MPL_ASSERT_NOT(( proto::matches< char_array, CharString > ));

Now, CharString does not match array types, only character string pointers.

The inverse problem is a little trickier: what if you wanted to match all character arrays, but not character pointers? As mentioned above, the expression as_expr("hello") has the type proto::terminal< char const[ 6 ] >::type. If you wanted to match character arrays of arbitrary size, you could use proto::N, which is an array-size wildcard. The following grammar would match any string literal: proto::terminal< char const[ proto::N ] >.

Sometimes you need even more wiggle room when matching terminals. For example, maybe you're building a calculator EDSL and you want to allow any terminals that are convertible to double. For that, Proto provides the proto::convertible_to<> template. You can use it as: proto::terminal< proto::convertible_to< double > >.

There is one more way you can perform a fuzzy match on terminals. Consider the problem of trying to match a std::complex<> terminal. You can easily match a std::complex<float> or a std::complex<double>, but how would you match any instantiation of std::complex<>? You can use proto::_ here to solve this problem. Here is the grammar to match any std::complex<> instantiation:

struct StdComplex
  : proto::terminal< std::complex< proto::_ > >
{};

When given a grammar like this, Proto will deconstruct the grammar and the terminal it is being matched against and see if it can match all the constituents.


PrevUpHomeNext