1[/ 2 (C) Copyright Edward Diener 2011-2015 3 Distributed under the Boost Software License, Version 1.0. 4 (See accompanying file LICENSE_1_0.txt or copy at 5 http://www.boost.org/LICENSE_1_0.txt). 6] 7 8[section:vmd_identifier Identifiers] 9 10An identifier in VMD is either of two lower-level preprocessor possibilities: 11 12* a preprocessing token 'identifier', which is essentially a sequence 13of alphanumeric characters and the underscore 14character with the first character not being a numeric character. 15* a preprocessing token 'pp-number' that is an integral literal token. 16 17Here are some examples: 18 19 SOME_NAME 20 _SOME_NAME 21 SOME_123_NAME 22 some_123_name 23 sOMe_123_NAmE 24 2367 25 43e11 26 0 27 22 28 654792 29 0x1256 30 31[heading Problem testing any identifier] 32 33One of the difficulties with identifiers in preprocessor metaprogramming 34is safely testing for a particular one. VMD has a means of doing this within 35a particular constraint for the characters that serve as the input. 36 37The constraint is that the beginning input character, ignoring any whitespace, passed 38as the input to test must be either: 39 40* an identifier character, ie. an alphanumeric or an underscore 41* the left parenthesis of a tuple 42 43and if the first character is not the left parenthesis of a tuple 44the remaining characters must be alphanumeric or an underscore until a space character 45or end of input occurs. 46 47If this is not the case the behavior is undefined, and most likely 48a preprocessing error will occur. 49 50Given the input: 51 52 's_anything' : can be tested 53 'S_anything' : can be tested 54 's_anYthiNg' : can be tested 55 '_anything' : can be tested 56 '_Anything' : can be tested 57 '_anytHIng' : can be tested 58 '24' : can be tested 59 '245e2' : can be tested 60 '(anything)' : can be tested, tuple 61 '(anything) anything' : can be tested, tuple and further input 62 'anything anything' : can be tested, identifier followed by space character 63 64 '%_anything' : undefined behavior and most likely a preprocessing error due to the constraint 65 '(_anything' : undefined behavior and most likely a preprocessing error due to the constraint, since a single '(' does not form a tuple 66 '44.3' : undefined behavior and most likely a preprocessing error due to the constraint since '.' is not alphanumeric 67 68[heading Identifying an identifier] 69 70In VMD the only way an identifier can be identified in preprocessor input is by a process called 71registration. In order to 'register' an identifier to be recognized by VMD the end-user must create, 72for every identifier to be recognized, an object-like macro whose form is: 73 74 #define BOOST_VMD_REGISTER_identifier (identifier) 75 76where 'identifier' is a particular identifier we wish to identify. This is called in 77VMD a registration macro. 78 79It is recommended that such registration macros be created in a header file which 80can be included before the end-user uses the identifier macros of VMD. 81 82If a particular registration macro occurs more than once it is 83not a preprocessing error, so duplicating a registration macro will not lead to any problems 84since each registration macro of the same name will have the exact same object-like macro 85expansion. 86 87Within a given translation unit it could potentially happen 88that registration macros have been included by header files which a particular end-user 89of VMD has not created. This should also not lead to particular problems since registration 90is a process for adding identifiers for any particular translation unit. As we shall see 91VMD has macros for not only finding any identifier in preprocessor input but for also finding 92any particular identifier in preprocessor input. 93 94[heading Testing for an identifier macro] 95 96The specific macro used to test for an identifier in VMD is called BOOST_VMD_IS_IDENTIFIER. 97The macro takes a required parameter of variadic data which is the input against which to test. 98 99When we invoke BOOST_VMD_IS_IDENTIFIER it returns 1 if the input represents any 100registered identifier, otherwise it returns 0. 101 102As an example: 103 104 #include <boost/vmd/is_identifier.hpp> 105 106 #define BOOST_VMD_REGISTER_yellow (yellow) 107 #define BOOST_VMD_REGISTER_green (green) 108 #define BOOST_VMD_REGISTER_blue (blue) 109 110 BOOST_VMD_IS_IDENTIFIER(some_input) // returns 1 if 'some_input' is 'yellow','green', or 'blue' 111 BOOST_VMD_IS_IDENTIFIER(some_input) // returns 0 if 'some_input' is 'purple' 112 113Only registered identifiers can be found in VMD as identifiers. 114 115[heading Detecting a particular identifier] 116 117Although registering an identifier allows VMD to recognize the string of characters 118as a VMD identifier, the ability to detect a particular identifier needs the end-user 119to define another macro: 120 121 #define BOOST_VMD_DETECT_identifier_identifier 122 123where 'identifier' is a particular identifier we wish to detect. This object-like 124macro expands to no output. 125 126Like the registration macro multiple detection macros of the same identifier 127in a translation unit does not cause a compiler problem since the exact same 128object-like macro occurs. 129 130The term for creating this macro is that we have potentially 'pre-detected' 131the identifier and I will use the term pre-detected as the process of creating 132the BOOST_VMD_DETECT macro. 133 134The ability to detect that a VMD identifier is a particular identifier is used 135in VMD macros when data is compared for equality/inequality as well as when we 136want to match an identifier against a set of other identifiers. These situations 137will be explained later in the documentation when the particular macro functionality 138is discussed. If the programmer never uses the functionality which these situations 139encompass there is no need to use pre-detection for a registered identifier. 140 141[heading Parsing identifier constraints and undefined behavior] 142 143The reason that the identifier constraints mentioned above exist is that the 144technique for parsing identifiers, once it is determined that the input 145being parsed does not begin with a set of parentheses, uses preprocessor 146concatenation in its parsing. This technique involves the preprocessor '##' 147operator to concatenate input, and examine the results of that concatenation. 148 149When preprocessor concatenation is used the result of the concatenation must 150be a valid preprocessing token, else the behavior of the preprocessor is undefined. 151In C++ 'undefined behavior' in general means that anything can happen. In practical 152use when preprocessor concatenation does not produce a valid preprocessing token, 153a compiler is most likely to generate a preprocessing error. If the compiler chooses 154not to issue a preprocessing error the outcome will always be correct and mean that 155parsing an identifier will fail. But because the outcome is undefined behavior there 156is no absolute way that the programmer can determine what the outcome will be when 157preprocessor concatenation is used and the input being parsed contains 158preprocessor input which does not meet the constraints for parsing an identifier 159mentioned at the beginning of this topic. 160 161In this documentation I will be using the abbreviation 'UB' as the shortened form 162of 'undefined behavior' to denote the particular occurrence where VMD attempts to 163parse preprocessor input using preprocessor concatenation and undefined behavior 164will occur. 165 166[heading Usage] 167 168To use the BOOST_VMD_IS_IDENTIFIER macro either include the general header: 169 170 #include <boost/vmd/vmd.hpp> 171 172or include the specific header: 173 174 #include <boost/vmd/is_identifier.hpp> 175 176[endsect] 177