1 /*
2 ** cdecl -- C gibberish translator
3 ** src/cdeck_keyword.cpp
4 **
5 ** Copyright (C) 2021 Paul J. Lucas
6 **
7 ** This program is free software: you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation, either version 3 of the License, or
10 ** (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /**
22 * @file
23 * Defines helper macros, data structures, variables, functions, and the
24 * tokenizer for C/C++ declarations.
25 */
26
27 // local
28 #include "pjl_config.h" /* must go first */
29 #include "cdecl_keyword.h"
30 #include "literals.h"
31
32 /// @cond DOXYGEN_IGNORE
33
34 // standard
35 #include <assert.h>
36 #include <string.h>
37
38 /// @endcond
39
40 ///////////////////////////////////////////////////////////////////////////////
41
42 /**
43 * Specify that the previosuly given literal is a synonym for the given
44 * language-specific literals.
45 *
46 * @param ALWAYS_FIND If `true`, always find this synonym, even when explaining
47 * C/C++.
48 * @param ... Array of c_lang_lit.
49 *
50 * @sa #CDECL_KEYWORDS for examples.
51 */
52 #define C_SYN(ALWAYS_FIND,...) \
53 (ALWAYS_FIND), 0, (c_lang_lit_t const[]){ __VA_ARGS__ }
54
55 /**
56 * Special-case of #C_SYN when there is only one language(s)/literal pair.
57 *
58 * @param ALWAYS_FIND If `true`, always find this synonym, even when explaining
59 * C/C++.
60 * @param C_KEYWORD The C/C++ keyword literal (`L_xxx`) that is the synonym.
61 *
62 * @sa #CDECL_KEYWORDS for examples.
63 */
64 #define C_SY1(ALWAYS_FIND,C_KEYWORD) \
65 C_SYN( (ALWAYS_FIND), { LANG_ANY, C_KEYWORD } )
66
67 /**
68 * Specify that the previosuly given literal maps to Bison tokan \a Y_ID.
69 *
70 * @param Y_ID The Bison token ID (`Y_xxx`).
71 *
72 * @sa #CDECL_KEYWORDS for examples.
73 */
74 #define TOKEN(Y_ID) false, (Y_ID), NULL
75
76 /**
77 * All cdecl keywords that are (mostly) _not_ C/C++ keywords.
78 *
79 * To have a literal for a cdecl keyword map to its corresponding token, use
80 * #TOKEN:
81 *
82 * // The "aligned" literal maps to the Y_ALIGNED token:
83 * { L_ALIGNED, TOKEN( Y_ALIGNED ) }
84 *
85 * To have a literal that is a synonym for another literal for a cdecl keyword
86 * map to the other literal's same token, use #TOKEN with the other literal's
87 * token:
88 *
89 * // The "align" literal synonym also maps to the Y_ALIGNED token:
90 * { L_ALIGN, TOKEN( Y_ALIGNED ) },
91 *
92 * To have a literal that is pseudo-English be a synonym for exactly one
93 * corresponding C/C++ keyword literal, but only when converting pseudo-English
94 * to gibberish, use #C_SY1 with `false`:
95 *
96 * // The "atomic" literal is a synonym for the "_Atomic" literal, but
97 * // only when converting from pseudo-English to gibberish:
98 * { L_ATOMIC, C_SY1( false, L__ATOMIC ) },
99 *
100 * To do the same, but allow the literal at any time (i.e., also when
101 * converting gibberish to pseudo-English), use #C_SY1 with `true`:
102 *
103 * // The "imaginary" literal is always a synonym for the "_Imaginary"
104 * // literal.
105 * { L_IMAGINARY, C_SY1( true, L__IMAGINARY ) },
106 *
107 * To have a literal that is pseudo-English be a synonym for more than one
108 * corresponding C/C++ keyword depending on the current language, use #C_SYN
109 * with the last row always containing #LANG_ANY:
110 *
111 * // The "noreturn" literal is a synonym for the "_Noreturn" literal only
112 * // in C11 and later.
113 * { L_NORETURN, C_SYN( true,
114 * { { LANG_C_MIN(11), L__NORETURN },
115 * { LANG_ANY, L_NORETURN } } ) },
116 *
117 * Exceptions are `bool`, `complex`, `const`, and `volatile` that are included
118 * here as cdecl keywords so each maps to its language-specific literal.
119 *
120 * @sa AC_CDECL_KEYWORDS
121 * @sa CDECL_COMMANDS
122 * @sa C_KEYWORDS
123 */
124 static cdecl_keyword_t const CDECL_KEYWORDS[] = {
125 { L_ADDRESS, TOKEN( Y_ADDRESS ) },
126 { L_ALIGN, TOKEN( Y_ALIGNED ) },
127 { L_ALIGNED, TOKEN( Y_ALIGNED ) },
128 { L_ALL, TOKEN( Y_ALL ) },
129 { L_APPLE_BLOCK, TOKEN( Y_APPLE_BLOCK ) },
130 { L_ARRAY, TOKEN( Y_ARRAY ) },
131 { L_AS, TOKEN( Y_AS ) },
132 { L_ATOMIC, C_SY1( false, L__ATOMIC ) },
133 { L_AUTOMATIC, C_SY1( false, L_AUTO ) },
134 { L_BITS, TOKEN( Y_BITS ) },
135 { L_BOOL, C_SYN( true,
136 { LANG_C_MIN(99), L__BOOL },
137 { LANG_ANY, L_BOOL } ) },
138 { L_BYTES, TOKEN( Y_BYTES ) },
139 { L_CARRIES, TOKEN( Y_CARRIES ) },
140 { H_CARRIES_DEPENDENCY,
141 C_SY1( false, L_CARRIES_DEPENDENCY ) },
142 { L_CAST, TOKEN( Y_CAST ) },
143 { L_CHARACTER, C_SY1( false, L_CHAR ) },
144 { L_COMPLEX, C_SYN( true,
145 { LANG_C_MAX(95), L_GNU___COMPLEX },
146 { LANG_C_MIN(99), L__COMPLEX },
147 { LANG_ANY, L_COMPLEX } ) },
148 { L_COMMAND, TOKEN( Y_COMMANDS ) },
149 { L_COMMANDS, TOKEN( Y_COMMANDS ) },
150 { L_CONST, C_SYN( false,
151 { LANG_C_KNR, L_GNU___CONST },
152 { LANG_ANY, L_CONST } ) },
153 { L_CONSTANT, C_SYN( false,
154 { LANG_C_KNR, L_GNU___CONST },
155 { LANG_ANY, L_CONST } ) },
156 { L_CONSTRUCTOR, TOKEN( Y_CONSTRUCTOR ) },
157 { L_CONV, TOKEN( Y_CONVERSION ) },
158 { L_CONVERSION, TOKEN( Y_CONVERSION ) },
159 { L_CTOR, TOKEN( Y_CONSTRUCTOR ) },
160 { L_DECLARE, TOKEN( Y_DECLARE ) },
161 { L_DEFAULTED, C_SY1( false, L_DEFAULT ) },
162 { L_DEFINE, TOKEN( Y_DEFINE ) },
163 { L_DELETED, C_SY1( false, L_DELETE ) },
164 { L_DEPENDENCY, TOKEN( Y_DEPENDENCY ) },
165 { L_DESTRUCTOR, TOKEN( Y_DESTRUCTOR ) },
166 { L_DISCARD, TOKEN( Y_DISCARD ) },
167 { H_DOUBLE_PRECISION,
168 C_SY1( false, L_DOUBLE ) },
169 { L_DTOR, TOKEN( Y_DESTRUCTOR ) },
170 { L_DYNAMIC, TOKEN( Y_DYNAMIC ) },
171 { L_ENGLISH, TOKEN( Y_ENGLISH ) },
172 { L_ENUMERATION, C_SY1( false, L_ENUM ) },
173 { L_EVAL, TOKEN( Y_EVALUATION ) },
174 { L_EVALUATION, TOKEN( Y_EVALUATION ) },
175 { L_EXCEPT, TOKEN( Y_EXCEPT ) },
176 { L_EXIT, TOKEN( Y_QUIT ) },
177 { L_EXPLAIN, TOKEN( Y_EXPLAIN ) },
178 { L_EXPORTED, C_SY1( false, L_EXPORT ) },
179 { L_EXPR, TOKEN( Y_EXPRESSION ) },
180 { L_EXPRESSION, TOKEN( Y_EXPRESSION ) },
181 { L_EXTERNAL, C_SY1( false, L_EXTERN ) },
182 { H_FLOATING_POINT, C_SY1( false, L_FLOAT ) },
183 { L_FUNC, TOKEN( Y_FUNCTION ) },
184 { L_FUNCTION, TOKEN( Y_FUNCTION ) },
185 { L_HELP, TOKEN( Y_HELP ) },
186 { L_IMAGINARY, C_SYN( true,
187 { LANG_C_MIN(99), L__IMAGINARY },
188 { LANG_ANY, L_IMAGINARY } ) },
189 { L_INIT, TOKEN( Y_INITIALIZATION ) },
190 { L_INITIALIZATION, TOKEN( Y_INITIALIZATION ) },
191 { L_INTEGER, C_SY1( false, L_INT ) },
192 { L_INTO, TOKEN( Y_INTO ) },
193 { L_LEN, TOKEN( Y_LENGTH ) },
194 { L_LENGTH, TOKEN( Y_LENGTH ) },
195 { L_LINKAGE, TOKEN( Y_LINKAGE ) },
196 { L_LITERAL, TOKEN( Y_LITERAL ) },
197 { L_LOCAL, TOKEN( Y_LOCAL ) },
198 { L_MAYBE, TOKEN( Y_MAYBE ) },
199 { H_MAYBE_UNUSED, C_SY1( false, L_MAYBE_UNUSED ) },
200 { L_MBR, TOKEN( Y_MEMBER ) },
201 { L_MEMBER, TOKEN( Y_MEMBER ) },
202 { L_NO, TOKEN( Y_NO ) },
203 { H_NO_DISCARD, C_SY1( false, L_NODISCARD ) },
204 { H_NO_EXCEPT, C_SY1( false, L_NOEXCEPT ) },
205 { H_NO_EXCEPTION, C_SY1( false, L_NOEXCEPT ) },
206 { H_NO_RETURN, C_SYN( false,
207 { LANG_C_MIN(11), L__NORETURN },
208 { LANG_ANY, L_NORETURN } ) },
209 { H_NON_DISCARDABLE,
210 C_SY1( false, L_NODISCARD ) },
211 { H_NON_MBR, TOKEN( Y_NON_MEMBER ) },
212 { H_NON_MEMBER, TOKEN( Y_NON_MEMBER ) },
213 { H_NON_RETURNING, C_SYN( false,
214 { LANG_C_MIN(11), L__NORETURN },
215 { LANG_ANY, L_NORETURN } ) },
216 { H_NON_THROWING, C_SY1( false, L_THROW ) },
217 { H_NO_UNIQUE_ADDRESS,
218 C_SY1( false, L_NO_UNIQUE_ADDRESS ) },
219 { H_NON_UNIQUE_ADDRESS,
220 C_SY1( false, L_NO_UNIQUE_ADDRESS ) },
221 { L_NORETURN, C_SYN( true,
222 { LANG_C_MIN(11), L__NORETURN },
223 { LANG_ANY, L_NORETURN } ) },
224 { L_OF, TOKEN( Y_OF ) },
225 { L_OPER, TOKEN( Y_OPERATOR ) },
226 { L_OPTIONS, TOKEN( Y_OPTIONS ) },
227 { L_OVERRIDDEN, C_SY1( false, L_OVERRIDE ) },
228 { L_POINTER, TOKEN( Y_POINTER ) },
229 { L_PREDEF, TOKEN( Y_PREDEFINED ) },
230 { L_PREDEFINED, TOKEN( Y_PREDEFINED ) },
231 { L_PTR, TOKEN( Y_POINTER ) },
232 { L_PURE, TOKEN( Y_PURE ) },
233 { L_Q, TOKEN( Y_QUIT ) },
234 { L_QUIT, TOKEN( Y_QUIT ) },
235 { L_REF, TOKEN( Y_REFERENCE ) },
236 { L_REFERENCE, TOKEN( Y_REFERENCE ) },
237 { L_REINTERPRET, TOKEN( Y_REINTERPRET ) },
238 { L_RESTRICTED, C_SYN( false,
239 { LANG_C_MAX(95) | LANG_CPP_ANY, L_GNU___RESTRICT },
240 { LANG_ANY, L_RESTRICT } ) },
241 { L_RET, TOKEN( Y_RETURNING ) },
242 { L_RETURNING, TOKEN( Y_RETURNING ) },
243 { L_RVALUE, TOKEN( Y_RVALUE ) },
244 { L_SCOPE, TOKEN( Y_SCOPE ) },
245 { L_SET_COMMAND, TOKEN( Y_SET ) },
246 { L_SHOW, TOKEN( Y_SHOW ) },
247 { L_STRUCTURE, C_SY1( false, L_STRUCT ) },
248 { L_THREAD_LOCAL, C_SYN( true,
249 { LANG_C_MIN(11), L__THREAD_LOCAL },
250 { LANG_ANY, L_THREAD_LOCAL } ) },
251 { L_THREAD, TOKEN( Y_THREAD ) },
252 { H_THREAD_LOCAL, C_SYN( true,
253 { LANG_C_CPP_MAX(99,03), L_GNU___THREAD },
254 { LANG_C_MIN(11), L__THREAD_LOCAL },
255 { LANG_ANY, L_THREAD_LOCAL } ) },
256 { L_TO, TOKEN( Y_TO ) },
257 { L_TYPE, C_SY1( false, L_TYPEDEF ) },
258 { L_UNIQUE, TOKEN( Y_UNIQUE ) },
259 { L_UNUSED, TOKEN( Y_UNUSED ) },
260 { L_USER, TOKEN( Y_USER ) },
261 { H_USER_DEF, TOKEN( Y_USER_DEFINED ) },
262 { H_USER_DEFINED, TOKEN( Y_USER_DEFINED ) },
263 { L_VAR, TOKEN( Y_VARIABLE ) },
264 { L_VARARGS, TOKEN( Y_ELLIPSIS ) },
265 { L_VARIABLE, TOKEN( Y_VARIABLE ) },
266 { L_VARIADIC, TOKEN( Y_ELLIPSIS ) },
267 { L_VECTOR, TOKEN( Y_ARRAY ) },
268 { L_VOLATILE, C_SYN( false,
269 { LANG_C_KNR, L_GNU___VOLATILE },
270 { LANG_ANY, L_VOLATILE } ) },
271 { L_WIDTH, TOKEN( Y_WIDTH ) },
272
273 // Embedded C extensions
274 { L_EMC_ACCUM, C_SYN( true,
275 { LANG_C_99, L_EMC__ACCUM },
276 { LANG_ANY, NULL } ) },
277 { L_EMC_FRACT, C_SYN( true,
278 { LANG_C_99, L_EMC__FRACT },
279 { LANG_ANY, NULL } ) },
280 { L_EMC_SAT, C_SYN( false,
281 { LANG_C_99, L_EMC__SAT },
282 { LANG_ANY, NULL } ) },
283 { L_EMC_SATURATED, C_SYN( true,
284 { LANG_C_99, L_EMC__SAT },
285 { LANG_ANY, NULL } ) },
286
287 // Microsoft extensions
288 { L_MSC_CDECL, C_SY1( false, L_MSC___CDECL ) },
289 { L_MSC_CLRCALL, C_SY1( false, L_MSC___CLRCALL ) },
290 { L_MSC_FASTCALL, C_SY1( false, L_MSC___FASTCALL ) },
291 { L_MSC_STDCALL, C_SY1( false, L_MSC___STDCALL ) },
292 { L_MSC_THISCALL, C_SY1( false, L_MSC___THISCALL ) },
293 { L_MSC_VECTORCALL, C_SY1( false, L_MSC___VECTORCALL ) },
294 { L_MSC_WINAPI, C_SY1( true, L_MSC___STDCALL ) },
295
296 { NULL, TOKEN( 0 ) }
297 };
298
299 ////////// extern functions ///////////////////////////////////////////////////
300
cdecl_keyword_find(char const * s)301 cdecl_keyword_t const* cdecl_keyword_find( char const *s ) {
302 assert( s != NULL );
303 // the list is small, so linear search is good enough
304 for ( cdecl_keyword_t const *k = CDECL_KEYWORDS; k->literal != NULL; ++k ) {
305 if ( strcmp( s, k->literal ) == 0 )
306 return k;
307 } // for
308 return NULL;
309 }
310
cdecl_keyword_next(cdecl_keyword_t const * k)311 cdecl_keyword_t const* cdecl_keyword_next( cdecl_keyword_t const *k ) {
312 return k == NULL ? CDECL_KEYWORDS : (++k)->literal == NULL ? NULL : k;
313 }
314
315 ///////////////////////////////////////////////////////////////////////////////
316 /* vim:set et sw=2 ts=2: */
317