]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
10 | An identifier in VMD is either of two lower-level preprocessor possibilities: | |
11 | ||
12 | * a preprocessing token 'identifier', which is essentially a sequence | |
13 | of alphanumeric characters and the underscore | |
14 | character with the first character not being a numeric character. | |
15 | * a preprocessing token 'pp-number' that is an integral literal token. | |
16 | ||
17 | Here 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 | ||
33 | One of the difficulties with identifiers in preprocessor metaprogramming | |
34 | is safely testing for a particular one. VMD has a means of doing this within | |
35 | a particular constraint for the characters that serve as the input. | |
36 | ||
37 | The constraint is that the beginning input character, ignoring any whitespace, passed | |
38 | as 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 | ||
43 | and if the first character is not the left parenthesis of a tuple | |
44 | the remaining characters must be alphanumeric or an underscore until a space character | |
45 | or end of input occurs. | |
46 | ||
47 | If this is not the case the behavior is undefined, and most likely | |
48 | a preprocessing error will occur. | |
49 | ||
50 | Given 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 | ||
70 | In VMD the only way an identifier can be identified in preprocessor input is by a process called | |
71 | registration. In order to 'register' an identifier to be recognized by VMD the end-user must create, | |
72 | for every identifier to be recognized, an object-like macro whose form is: | |
73 | ||
74 | #define BOOST_VMD_REGISTER_identifier (identifier) | |
75 | ||
76 | where 'identifier' is a particular identifier we wish to identify. This is called in | |
77 | VMD a registration macro. | |
78 | ||
79 | It is recommended that such registration macros be created in a header file which | |
80 | can be included before the end-user uses the identifier macros of VMD. | |
81 | ||
82 | If a particular registration macro occurs more than once it is | |
83 | not a preprocessing error, so duplicating a registration macro will not lead to any problems | |
84 | since each registration macro of the same name will have the exact same object-like macro | |
85 | expansion. | |
86 | ||
87 | Within a given translation unit it could potentially happen | |
88 | that registration macros have been included by header files which a particular end-user | |
89 | of VMD has not created. This should also not lead to particular problems since registration | |
90 | is a process for adding identifiers for any particular translation unit. As we shall see | |
91 | VMD has macros for not only finding any identifier in preprocessor input but for also finding | |
92 | any particular identifier in preprocessor input. | |
93 | ||
94 | [heading Testing for an identifier macro] | |
95 | ||
96 | The specific macro used to test for an identifier in VMD is called BOOST_VMD_IS_IDENTIFIER. | |
97 | The macro takes one required parameter which is the input against which to test. | |
98 | ||
99 | When we invoke BOOST_VMD_IS_IDENTIFIER it returns 1 if the input represents any | |
100 | registered identifier, otherwise it returns 0. | |
101 | ||
102 | As 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 | ||
113 | Essentially only registered identifiers can be found in VMD as identifiers. | |
114 | ||
115 | [heading Detecting a particular identifier] | |
116 | ||
117 | Although registering an identifier allows VMD to recognize the string of characters | |
118 | as a VMD identifier, the ability to detect a particular identifier needs the end-user | |
119 | to define another macro: | |
120 | ||
121 | #define BOOST_VMD_DETECT_identifier_identifier | |
122 | ||
123 | where 'identifier' is a particular identifier we wish to detect. This object-like | |
124 | macro expands to no output. | |
125 | ||
126 | Like the registration macro multiple detection macros of the same identifier | |
127 | in a translation unit does not cause a compiler problem since the exact same | |
128 | object-like macro occurs. | |
129 | ||
130 | The term for creating this macro is that we have potentially 'pre-detected' | |
131 | the identifier and I will use the term pre-detected as the process of creating | |
132 | the BOOST_VMD_DETECT macro. | |
133 | ||
134 | The ability to detect that a VMD identifier is a particular identifier is used | |
135 | in VMD macros when data is compared for equality/inequality as well as when we | |
136 | want to match an identifier against a set of other identifiers. These situations | |
137 | will be explained later in the documentation when the particular macro functionality | |
138 | is discussed. If the programmer never uses the functionality which these situations | |
139 | encompass there is no need to use pre-detection for a registered identifier. | |
140 | ||
141 | [heading Parsing identifiers and undefined behavior] | |
142 | ||
143 | The technique for parsing identifiers, once it is determined that the input | |
144 | being parsed does not begin with a set of parentheses, uses preprocessor | |
145 | concatenation in its parsing. This technique involves the preprocessor '##' | |
146 | operator to concatenate input, and examine the results of that concatenation. | |
147 | ||
148 | When preprocessor concatenation is used the result of the concatenation must | |
149 | be a valid preprocessing token, else the behavior of the preprocessor is undefined. | |
150 | In C++ 'undefined behavior' in general means that anything can happen. In practical | |
151 | use when preprocessor concatenation does not produce a valid preprocessing token, | |
152 | a compiler is most likely to generate a preprocessing error. If the compiler chooses | |
153 | not to issue a preprocessing error the outcome will always mean that parsing an | |
154 | identifier will fail. But because the outcome is undefined behavior there is no | |
155 | absolute way that the programmer can determine what the outcome will be when | |
156 | preprocessor concatenation is used and the input being parsed contains | |
157 | preprocessor input which does not meet the constraints for parsing an identifier | |
158 | mentioned at the beginning of this topic. | |
159 | ||
160 | In this documentation I will be using the abbreviation 'UB' as the shortened form | |
161 | of 'undefined behavior' to denote the particular occurrence where VMD attempts to | |
162 | parse preprocessor input using preprocessor concatenation and undefined behavior | |
163 | will occur. | |
164 | ||
165 | [heading Usage] | |
166 | ||
167 | To use the BOOST_VMD_IS_IDENTIFIER macro either include the general header: | |
168 | ||
169 | #include <boost/vmd/vmd.hpp> | |
170 | ||
171 | or include the specific header: | |
172 | ||
173 | #include <boost/vmd/is_identifier.hpp> | |
174 | ||
175 | [endsect] |