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