Boost logo

Boost :

Subject: Re: [boost] [preprocessor] check if a token is a keyword (was "BOOST_PP_IS_UNARY()")
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2010-08-17 00:21:36


On Mon, Aug 16, 2010 at 3:24 AM, Paul Mensonides <pmenso57_at_[hidden]> wrote:
> On 8/13/2010 7:52 AM, Lorenzo Caminiti wrote:
>>
>> Hello all,
>>
>> I asked this question before but received no answer: Is there any
>> problem in using `BOOST_PP_UNARY()` to check if a token matches a
>> predefined keyword as indicated by the code below?
>>
>> The following `IS_PUBLIC(token)` macro expands to 1 if `token` is
>> `public`, to 0 otherwise:
>>
>>    #define PUBLIC_public (1)
>>    #define IS_PUBLIC(token) BOOST_PP_IS_UNARY(BOOST_PP_CAT(PUBLIC_,
>> token))
>>
>>    IS_PUBLIC(public)    // Expand to 1.
>>    IS_PUBLIC(abc)       // Expand to 0.
>>
>> This works just fine on both GCC and MSVC. However, `BOOST_PP_UNARY()`
>> is only part of Boost.Preprocessor private API because:
>
> IS_PUBLIC(+) results in undefined behavior.  More generally, the result of
> token-pasting must result in a single (preprocessing) token.  So, for
> example, BOOST_PP_CAT(abc, 123) and BOOST_PP_CAT(+, +) are okay, but
> BOOST_PP_CAT(abc, 123.0) and BOOST_PP_CAT(+, -) are not.  Similarly for what
> you have above which will work provided everything used as an argument is an
> identifier (there are no "keywords" to the preprocessor) or a pp-number that
> doesn't contain any decimal points.

Yes, I am aware of this "limitation". However, for my application it
is not a problem to limit the argument of `IS_PUBLIC()` to
pp-identifiers and pp-numbers with no decimal points (if interested,
see "MY APPLICATION" below).

1) Out of curiosity, is there a way to implement `IS_PUBLIC()`
(perhaps without using `BOOST_PP_CAT()`) so it does not have this
limitation? (I could not think of any.)
2) Also, does the expansion of any of the following result in
undefined behavior? (I don't think so...)

    IS_PUBLIC(public abc) // Expand to 1.
    IS_PUBLIC(public::) // Expand to 1.
    IS_PUBLIC(public(abc, ::)) // Expand to 1.
    IS_PUBLIC(public (abc) (yxz)) // Expand to 1.

(My application relies on some of these expansions to work.)

MY APPLICATION

I am using `IS_PUBLIC()` and similar macros to program the
preprocessor to *parse* a Boost.Preprocessor sequence of tokens that
represents a function signature. For example:

    class c {
        public: void f(int x) const; // Usual function declaration.
    };

    class c {
        PARSE_FUNCTION_DECL( // Equivalent declaration using pp-sequences.
        (public) (void) (f)( (int)(x) ) (const)
        );
    };

The parser macro above can say "the signature sequence starts with
`public` so this is a member function" at a preprocessor
metaprogramming level and then expand to special code as a library
might need to handle member functions. The parser macros can even do
some basic syntax error checking -- for example, if `(const)` is
specified as cv-qualifier at the end of the signature sequence of a
non-member function, the parser macro can check that and expand to a
compile-time error like `SYNTAX_ERROR_unexpected_cv_qualifier` (using
`BOOST_MPL_ASSERT_MSG()`).

Most of the tokens within C++ funciton signatures are composed of
pp-idenfitiers such as the words `public`, `void`, `f`, etc. There are
some exceptions like `,` to separate funciton parameters, `<`/`>` for
templates, `:` for constructors' member initializers, etc. The grammar
of my preprocessor parser macros requires the use of different tokens
in these cases. For example, parenthesis `(`/`)` are used for
templates instead of `<`/`>`:

    template< typename T > f(T x); // Usual.

    PARSE_FUNCTION_DECL( // PP-sequence.
    (template)( (typename)(T) ) (f)( (T)(x) )
    );

(Instead of `(template)(<) (typename) (T) (>) (f)( (T)(x) )` which
will have caused the parser macro to fail when inspecting `(<)` via
one of the `IS_XXX()` macros as per the limitation from using
`BOOST_PP_CAT()` mentioned above.)

The grammar of my preprocessor parser macros clearly documents that
only pp-identifiers can be passed as tokens of the function signature
sequence. Therefore, the "limitation" of `IS_PUBLIC()` indicated above
is not a problem for my application.

Thank you very much.

-- 
Lorenzo

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk