3 .Dt LIBCDECL \&3 "Cdecl99 Developer's Manual"
6 .Nd C library for making sense of C declarations
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);
14 .Fd size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl);
15 .Fd size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl);
17 .Fd const struct cdecl_error *cdecl_get_error(void);
19 .Fd int cdecl_spec_kind(struct cdecl_declspec *spec);
20 .Fd bool cdecl_is_abstract(struct cdecl_declarator *declarator);
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
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
38 reserves all identifiers beginning with either
42 in both the tag and ordinary identifier namespaces.
43 All external names beginning with
45 are reserved, and the library headers may define object-like macros beginning
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.
57 External names beginning with
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
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
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
70 The AST is represented by the following structure:
71 .Bd -literal -offset indent
74 struct cdecl_declspec *specifiers;
75 struct cdecl_declarator *declarators;
79 At the top level, every declaration consists of one or more declaration
80 specifiers followed by one or more full declarators; hence, the
84 members are always non-null.
85 A declaration with more than one declarator is represented by using the
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.
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;
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.
109 .Fd int cdecl_spec_kind(struct cdecl_declspec *spec);
111 can be used to determine what kind of specifier
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 .
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 .
140 member points to a C string containing the struct tag.
141 .It Dv CDECL_TYPE_UNION Ta Fa union No type specifier .
144 member points to a C string containing the union tag.
145 .It Dv CDECL_TYPE_ENUM Ta Fa enum No type specifier .
148 member points to a C string containing the enum tag.
149 .It Dv CDECL_TYPE_IDENT Ta Typedef name type specifier .
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 .
164 Declarators are represented by the structure:
165 .Bd -literal -offset indent
166 struct cdecl_declarator {
167 struct cdecl_declarator *child;
171 struct cdecl_pointer pointer;
172 struct cdecl_array array;
173 struct cdecl_function function;
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
182 This relationship is expressed by the
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
190 to describe this inverted child relationship: we consider the outermost
193 as the declaration's base type (found amongst the declaration specifiers,
194 .No e.g. Li int , const unsigned long ,
197 The five types of declarators, described below, are distinguished by the
200 Each declarator (except null declarators) carries additional information
201 specific to its type, which corresponds to the members of the union
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
209 .It Dv CDECL_DECL_IDENT Ta Va ident Ta Declares an identifier. This
210 declarator has a NULL
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
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
223 to indicate an abstract declarator; that is, one which does not declare any
225 Such declarators appear in type names and possibly function parameters.
226 An identifier declarator has the obvious meaning; the
228 union member points to the C string containing the identifier.
230 Since a null declarator may be deeply nested in the declarator chain, the
233 .Fd bool cdecl_is_abstract(struct cdecl_declarator *declarator);
235 can be used to determine whether or not a given declarator declares an
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;
247 member is non-null, then it points to the first element of a singly-linked list
249 .Ss Array Declarators
250 .Bd -literal -offset indent
259 member is non-null, then this declarator is a variable-length array declarator.
262 member points to an identifier if it is known, else it points to the empty
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;
278 is null, then this is a non-prototype function declarator.
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).
287 is true, then the function is variadic.
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.
294 isn't a C compiler, there is no way for its parser to tell these two kinds of
300 Such functions will be documented as indicating an error condition in a
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.
306 provides a structure which describes a particular error.
307 .Bd -literal -offset indent
316 member identifies the sort of error which has occurred, while the
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
321 .Fd const struct cdecl_error *cdecl_get_error(void);
323 which returns a pointer to the error structure most recently generated in the
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
331 by the same thread, other than another call to
332 .Fn cdecl_get_error .
336 call has indicated that an error occurred in the current thread, the result
340 .Sh PARSING DECLARATIONS
341 To parse a declaration, the function
343 .Fd struct cdecl *cdecl_parse_decl(const char *declstr);
346 The provided string is parsed as a C declaration.
347 If successful, this function returns a pointer to an abstract syntax tree
348 representing the declaration.
349 If the parse fails for any reason, the function returns NULL.
351 Similarly, English declarations can be parsed by using the function
353 .Fd struct cdecl *cdecl_parse_english(const char *english);
355 When the AST is no longer needed, it must be freed by passing it to the
358 .Fd void cdecl_free(struct cdecl *decl);
359 .Sh RENDERING DECLARATIONS
360 After parsing, the abstract syntax tree can be rendered to a string for output.
363 .Fd size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl);
365 to format the AST pointed to by
367 into something resembling English.
368 At most one full declarator is rendered in this way; for declarations with more
369 than one full declarator, this function should be called on each
371 in the singly-linked list.
373 In a manner similar to that of
377 bytes, including the '\\0' terminator, are written to
381 is zero, it is acceptable for
383 to be a null pointer.
384 Regardless, the function returns the number of characters that would be written
389 were long enough, not including the '\\0' terminator.
390 Thus, the entire string was written if a value less than
394 Similarly, the function
396 .Fd size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl);
398 will render the AST pointed to by
402 Nick Bowler <nbowler@draconx.ca>
404 Copyright \(co 2011\(en2012, 2021 Nick Bowler
406 Permission is granted to copy, distribute and/or modify this manual under the
407 terms of the GNU General Public License as published by the Free Software
408 Foundation, either version 3 of the License, or (at your option) any later