]> git.draconx.ca Git - cdecl99.git/blob - doc/libcdecl.3
Expand some sections of the libcdecl manual.
[cdecl99.git] / doc / libcdecl.3
1 .Dd July 27, 2023
2 .Os cdecl99
3 .Dt LIBCDECL \&3 "Cdecl99 Developer's Manual"
4 .Sh NAME
5 .Nm libcdecl
6 .Nd C library for making sense of C declarations
7 .Sh SYNOPSIS
8 .Fd #include <cdecl.h>
9 .Pp
10 .Fd struct cdecl *cdecl_parse_decl(const char *declstr);
11 .Fd struct cdecl *cdecl_parse_english(const char *english);
12 .Fd void cdecl_free(struct cdecl *decl);
13 .Pp
14 .Fd size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl);
15 .Fd size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl);
16 .Pp
17 .Fd const struct cdecl_error *cdecl_get_error(void);
18 .Pp
19 .Fd int cdecl_spec_kind(struct cdecl_declspec *spec);
20 .Fd bool cdecl_is_abstract(struct cdecl_declarator *declarator);
21 .Sh DESCRIPTION
22 .Nm
23 provides support for parsing C declarations and translating them to something
24 resembling English and vice-versa.
25 This manual describes the programmers' interface only; for details such as what
26 C language features are supported or the syntax of English declarations, please
27 see the
28 .Xr cdecl99 1
29 manual page.
30 .Pp
31 .Nm
32 is intended to be portable to any system with a working C implementation that
33 at least makes an effort to support C99.
34 The library is thread-safe when appropriate facilities exist and are enabled at
35 build time.
36 .Sh NAMESPACE
37 .Nm
38 reserves all identifiers beginning with either
39 .Li cdecl_
40 or
41 .Li CDECL_
42 in both the tag and ordinary identifier namespaces.
43 All external names beginning with
44 .Li cdecl_
45 are reserved, and the library headers may define object-like macros beginning
46 with
47 .Li CDECL_ .
48 The
49 .Nm
50 library headers may use other identifiers where they do not pollute the global
51 namespaces, such as struct members or function parameter names.
52 Such internal identifiers shall not contain any upper-case letters.
53 As these internal identifiers can only conflict with object-like macros, this
54 practice is safe as long as the convention of defining object-like macros using
55 upper-case letters is adhered to.
56 .Pp
57 External names beginning with
58 .Li cdecl
59 followed by two consecutive underscores are not considered part of the ABI and
60 are thus subject to change at any time.
61 .Sh ABSTRACT SYNTAX TREE
62 The functions in
63 .Nm
64 generally operate on an abstract syntax tree representing a C declaration.
65 A string is parsed into an AST which can be subsequently rendered into another
66 format.
67 Since some information about the original string is discarded when generating
68 the AST, parsing a declaration and then rendering to the same format is not the
69 identity function.
70 The AST is represented by the following structure:
71 .Bd -literal -offset indent
72 struct cdecl {
73         struct cdecl *next;
74         struct cdecl_declspec   *specifiers;
75         struct cdecl_declarator *declarators;
76 };
77 .Ed
78 .Pp
79 At the top level, every declaration consists of one or more declaration
80 specifiers followed by one or more full declarators; hence, the
81 .Va specifiers
82 and
83 .Va declarators
84 members are always non-null.
85 A declaration with more than one declarator is represented by using the
86 .Va next
87 member to form a singly-linked list of ASTs, one element for each declarator.
88 In the case of the toplevel declaration, the declaration specifiers will be
89 identical for all elements of the list.
90 But when the same kind of list is used to represent function parameters, the
91 specifiers may be different for each element.
92 .Pp
93 There are four kinds of declaration specifiers: storage-class, function and
94 type specifiers, as well as type qualifiers.
95 All are represented by the structure:
96 .Bd -literal -offset indent
97 struct cdecl_declspec {
98         struct cdecl_declspec *next;
99         unsigned type;
100         char *ident;
101 };
102 .Ed
103 .Pp
104 When multiple declaration specifiers are present, they are represented as
105 a singly-linked list, one element for each specifier.
106 Specifiers can appear in any order.
107 The function
108 .Pp
109 .Fd int cdecl_spec_kind(struct cdecl_declspec *spec);
110 .Pp
111 can be used to determine what kind of specifier
112 .Fa spec
113 is.  The result is one of the following values:
114 .Bl -column ".Dv CDECL_SPEC_TYPE"
115 .It Em Kind            Ta Em Description
116 .It Dv CDECL_SPEC_TYPE Ta Type specifier .
117 .It Dv CDECL_SPEC_STOR Ta Storage-class specifier .
118 .It Dv CDECL_SPEC_QUAL Ta Type qualifier .
119 .It Dv CDECL_SPEC_FUNC Ta Function specifier .
120 .El
121 .Pp
122 The following table describes all the possible types of declaration specifiers:
123 .Bl -column ".Dv CDECL_TYPE_IMAGINARY"
124 .It Em Em Type              Ta Em Description
125 .It Dv CDECL_TYPE_VOID      Ta Fa void       No type specifier .
126 .It Dv CDECL_TYPE_CHAR      Ta Fa char       No type specifier .
127 .It Dv CDECL_TYPE_SHORT     Ta Fa short      No type specifier .
128 .It Dv CDECL_TYPE_INT       Ta Fa int        No type specifier .
129 .It Dv CDECL_TYPE_LONG      Ta Fa long       No type specifier .
130 .It Dv CDECL_TYPE_FLOAT     Ta Fa float      No type specifier .
131 .It Dv CDECL_TYPE_DOUBLE    Ta Fa double     No type specifier .
132 .It Dv CDECL_TYPE_SIGNED    Ta Fa signed     No type specifier .
133 .It Dv CDECL_TYPE_UNSIGNED  Ta Fa unsigned   No type specifier .
134 .It Dv CDECL_TYPE_BOOL      Ta Fa _Bool      No type specifier .
135 .It Dv CDECL_TYPE_COMPLEX   Ta Fa _Comples   No type specifier .
136 .It Dv CDECL_TYPE_IMAGINARY Ta Fa _Imaginary No type specifier .
137 .It Dv CDECL_TYPE_STRUCT    Ta Fa struct     No type specifier .
138 The
139 .Va ident
140 member points to a C string containing the struct tag.
141 .It Dv CDECL_TYPE_UNION     Ta Fa union      No type specifier .
142 The
143 .Va ident
144 member points to a C string containing the union tag.
145 .It Dv CDECL_TYPE_ENUM      Ta Fa enum       No type specifier .
146 The
147 .Va ident
148 member points to a C string containing the enum tag.
149 .It Dv CDECL_TYPE_IDENT     Ta Typedef name type specifier .
150 The
151 .Va ident
152 member points to a C string containing the identifier.
153 .It Dv CDECL_STOR_TYPEDEF   Ta Fa typedef    No storage-class specifier .
154 .It Dv CDECL_STOR_EXTERN    Ta Fa extern     No storage-class specifier .
155 .It Dv CDECL_STOR_STATIC    Ta Fa static     No storage-class specifier .
156 .It Dv CDECL_STOR_AUTO      Ta Fa auto       No storage-class specifier .
157 .It Dv CDECL_STOR_REGISTER  Ta Fa register   No storage-class specifier .
158 .It Dv CDECL_QUAL_RESTRICT  Ta Fa restrict   No type qualifier .
159 .It Dv CDECL_QUAL_VOLATILE  Ta Fa volatile   No type qualifier .
160 .It Dv CDECL_QUAL_CONST     Ta Fa const      No type qualifier .
161 .It Dv CDECL_FUNC_INLINE    Ta Fa inline     No function specifier .
162 .El
163 .Pp
164 Declarators are represented by the structure:
165 .Bd -literal -offset indent
166 struct cdecl_declarator {
167         struct cdecl_declarator *child;
168         unsigned type;
169         union {
170                 char *ident;
171                 struct cdecl_pointer  pointer;
172                 struct cdecl_array    array;
173                 struct cdecl_function function;
174         } u;
175 };
176 .Ed
177 .Pp
178 With the exception of function parameters (which are handled separately),
179 declarators form a chain from
180 .Do outermost Dc to Do innermost Dc
181 declarator.
182 This relationship is expressed by the
183 .Va child
184 struct member, which points to the next innermost declarator in the chain.
185 Unfortunately, C's declaration syntax is, in a sense, inside-out.
186 Thus, one needs to follow the chain backwards (from innermost to outermost) to
187 understand the semantic relationship between declarators in the chain.
188 In the next section, we will use the word
189 .Va parent
190 to describe this inverted child relationship: we consider the outermost
191 declarator's
192 .Va parent
193 as the declaration's base type (found amongst the declaration specifiers,
194 .No e.g. Li int , const unsigned long ,
195 etc.)
196 .Pp
197 The five types of declarators, described below, are distinguished by the
198 .Va type
199 struct member.
200 Each declarator (except null declarators) carries additional information
201 specific to its type, which corresponds to the members of the union
202 .Va u .
203 The possible values are described by the following table:
204 .Bl -column ".Dv CDECL_DECL_FUNCTION" ".Em Union Member"
205 .It Em Declarator Type     Ta Em Union Member Ta Em Description
206 .It Dv CDECL_DECL_NULL     Ta (none)          Ta Declares nothing.  This
207 declarator terminates the declarator chain, and has a NULL
208 .Va child .
209 .It Dv CDECL_DECL_IDENT    Ta Va ident        Ta Declares an identifier.  This
210 declarator has a NULL
211 .Va child .
212 .It Dv CDECL_DECL_POINTER  Ta Va pointer      Ta Declares a pointer, as in
213 .Do pointer to Va parent Dc
214 .It Dv CDECL_DECL_ARRAY    Ta Va array        Ta Declares an array, as in
215 .Do array of Va parent Dc
216 .It Dv CDECL_DECL_FUNCTION Ta Va function     Ta Declares a function, as in
217 .Do function returning Va parent Dc
218 .El
219 .Ss Terminal Declarators
220 Null and identifier declarators have no children and are thus leaf nodes.
221 A null declarator is not strictly a C language construct, but is used by
222 .Nm
223 to indicate an abstract declarator; that is, one which does not declare any
224 identifier.
225 Such declarators appear in type names and possibly function parameters.
226 An identifier declarator has the obvious meaning; the
227 .Va ident
228 union member points to the C string containing the identifier.
229 .Pp
230 Since a null declarator may be deeply nested in the declarator chain, the
231 function
232 .Pp
233 .Fd bool cdecl_is_abstract(struct cdecl_declarator *declarator);
234 .Pp
235 can be used to determine whether or not a given declarator declares an
236 identifier.
237 The result is true if and only if the declarator is abstract.
238 .Ss Pointer Declarators
239 .Bd -literal -offset indent
240 struct cdecl_pointer {
241         struct cdecl_declspec *qualifiers;
242 };
243 .Ed
244 .Pp
245 If the
246 .Va qualifiers
247 member is non-null, then it points to the first element of a singly-linked list
248 of type qualifiers.
249 .Ss Array Declarators
250 .Bd -literal -offset indent
251 struct cdecl_array {
252         char *vla;
253         uintmax_t length;
254 };
255 .Ed
256 .Pp
257 If the
258 .Va vla
259 member is non-null, then this declarator is a variable-length array declarator.
260 The
261 .Va vla
262 member points to an identifier if it is known, else it points to the empty
263 string.
264 Otherwise, if
265 .Va length
266 is positive, then this is an array declarator with the specified length.
267 Otherwise, this is an incomplete array declarator.
268 .Ss Function Declarators
269 .Bd -literal -offset indent
270 struct cdecl_function {
271         struct cdecl *parameters;
272         _Bool variadic;
273 };
274 .Ed
275 .Pp
276 If
277 .Va parameters
278 is null, then this is a non-prototype function declarator.
279 Otherwise,
280 .Va parameters
281 points to the first element of a singly-linked list of declarations
282 representing the function parameters.
283 Note that, unlike toplevel declarations, each function parameter has exactly
284 one full declarator (abstract or otherwise).
285 If
286 .Va variadic
287 is true, then the function is variadic.
288 .Pp
289 Note that old-style function declarations with non-empty identifier lists are
290 not directly represented here: this is because they are syntactically identical
291 to a prototype where every parameter is a typedef name.
292 Since
293 .Nm
294 isn't a C compiler, there is no way for its parser to tell these two kinds of
295 declarations apart.
296 .Sh ERROR HANDLING
297 Some functions in
298 .Nm
299 can fail.
300 Such functions will be documented as indicating an error condition in a
301 particular way.
302 It is sometimes necessary to know more about a particular error in order to
303 print an informative error message or perform some other action.
304 To facilitate this,
305 .Nm
306 provides a structure which describes a particular error.
307 .Bd -literal -offset indent
308 struct cdecl_error {
309         unsigned code;
310         const char *str;
311 };
312 .Ed
313 .Pp
314 The
315 .Va code
316 member identifies the sort of error which has occurred, while the
317 .Va str
318 member points to a string containing a human-readable description of the error.
319 This error information can be retrieved by calling the function
320 .Pp
321 .Fd const struct cdecl_error *cdecl_get_error(void);
322 .Pp
323 which returns a pointer to the error structure most recently generated in the
324 current thread.
325 It is therefore thread-safe in the sense that errors occurring concurrently
326 in another thread will not interfere with a call to
327 .Fn cdecl_get_error .
328 The returned structure shall remain valid until the next call to any function
329 from
330 .Nm ,
331 by the same thread, other than another call to
332 .Fn cdecl_get_error .
333 .Pp
334 If no prior
335 .Nm
336 call has indicated that an error occurred in the current thread, the result
337 from calling
338 .Fn cdecl_get_error
339 is unspecified.
340 .Sh PARSING DECLARATIONS
341 The functions
342 .Pp
343 .Fd struct cdecl *cdecl_parse_decl(const char *decl);
344 .Fd struct cdecl *cdecl_parse_english(const char *english);
345 .Pp
346 parse a string into an abstract syntax tree representing the declaration.
347 The
348 .Fn cdecl_parse_decl
349 function interprets the string as C declaration syntax, while
350 .Fn cdecl_parse_english
351 uses the English declaration syntax.
352 If successful, a pointer to the abstract syntax tree representing the
353 declaration is returned.
354 If the parse fails for any reason, the function returns NULL, and
355 .Fn cdecl_get_error
356 may be used to retrieve the reason for failure.
357 .Pp
358 The manner in which memory is allocated by these functions for the returned
359 tree structure is unspecified.
360 In particular, multiple nodes may share memory or may be implemented as
361 read-only static allocations.
362 Thus, the caller should not directly modify any part of the returned structure,
363 as the results may be unexpected.
364 A copy should be made if modifications are required.
365 .Pp
366 When the structure returned by either parsing function is no longer needed, the
367 function
368 .Pp
369 .Fd void cdecl_free(struct cdecl *decl);
370 .Pp
371 may be used to release all memory allocations associated with that parse tree.
372 .Sh RENDERING DECLARATIONS
373 An abstract syntax tree (which may be the result of calling one of the parsing
374 functions or constructed explicitly by the program) can be rendered to a string
375 for output.
376 The functions
377 .Pp
378 .Fd size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl);
379 .Fd size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl);
380 .Pp
381 perform this rendering.
382 The
383 .Fa cdecl_declare
384 function produces output in C declaration syntax, while the
385 .Fa cdecl_explain
386 function produces output in the English declaration syntax.
387 .Pp
388 Only one top-level full declarator is rendered by each call; that is, these
389 functions do not traverse the
390 .Fa decl
391 linked list at the top level.
392 The caller can traverse this list to render multiple declarators.
393 In order to assist with generating C declaration syntax, as a special case,
394 when calling
395 .Fn cdecl_declare
396 the
397 .Va specifiers
398 member of the
399 .Fa decl
400 structure may be a null pointer.
401 In this case, only the declarator is rendered.
402 .Pp
403 The string is output in a manner similar to that of
404 .Xr snprintf 3 .
405 At most
406 .Fa n
407 bytes, including the '\\0' terminator, are written to
408 .Fa buf .
409 If
410 .Fa n
411 is zero, it is acceptable for
412 .Fa buf
413 to be a null pointer.
414 .Pp
415 The number of characters that would be written to
416 .Fa buf
417 if
418 .Fa n
419 were large enough is returned, not including the '\\0' terminator.
420 Hence the entire string was written if the returned value is less than
421 .Fa n .
422 If
423 .Fa n
424 is non-zero, the resulting string is '\\0' terminated even if it was truncated.
425 .Sh AUTHORS
426 Nick Bowler <nbowler@draconx.ca>
427 .Sh COPYRIGHT
428 Copyright \(co 2011\(en2012, 2021, 2023 Nick Bowler
429 .Pp
430 Permission is granted to copy, distribute and/or modify this manual under the
431 terms of the GNU General Public License as published by the Free Software
432 Foundation, either version 3 of the License, or (at your option) any later
433 version.
434 .Sh SEE ALSO
435 .Xr cdecl99 1