-.Dd July 18, 2011
+.Dd March 6, 2021
.Os cdecl99
.Dt LIBCDECL \&3 "Cdecl99 Developer's Manual"
.Sh NAME
.Sh DESCRIPTION
.Nm
provides support for parsing C declarations and translating them to something
-resembling English and vice-versa. This manual describes the programmers'
-interface only; for details such as what C language features are supported or
-the syntax of English declarations, please see the
+resembling English and vice-versa.
+This manual describes the programmers' interface only; for details such as what
+C language features are supported or the syntax of English declarations, please
+see the
.Xr cdecl99 1
manual page.
.Pp
.Nm
is intended to be portable to any system with a working C implementation that
-at least makes an effort to support C99. The library is thread-safe when
-appropriate facilities exist and are enabled at build time.
+at least makes an effort to support C99.
+The library is thread-safe when appropriate facilities exist and are enabled at
+build time.
.Sh NAMESPACE
.Nm
reserves all identifiers beginning with either
.Li cdecl_
or
.Li CDECL_
-in both the tag and ordinary identifier namespaces. All external names
-beginning with
+in both the tag and ordinary identifier namespaces.
+All external names beginning with
.Li cdecl_
are reserved, and the library headers may define object-like macros beginning
with
The
.Nm
library headers may use other identifiers where they do not pollute the global
-namespaces, such as struct members or function parameter names. Such internal
-identifiers shall not contain any upper-case letters. As these internal
-identifiers can only conflict with object-like macros, this practice is safe as
-long as the convention of defining object-like macros using upper-case letters
-is adhered to.
+namespaces, such as struct members or function parameter names.
+Such internal identifiers shall not contain any upper-case letters.
+As these internal identifiers can only conflict with object-like macros, this
+practice is safe as long as the convention of defining object-like macros using
+upper-case letters is adhered to.
.Pp
External names beginning with
.Li cdecl
.Nm
generally operate on an abstract syntax tree representing a C declaration.
A string is parsed into an AST which can be subsequently rendered into another
-format. Since some information about the original string is discarded when
-generating the AST, parsing a declaration and then rendering to the same format
-is not the identity function. The AST is represented by the following
-structure:
+format.
+Since some information about the original string is discarded when generating
+the AST, parsing a declaration and then rendering to the same format is not the
+identity function.
+The AST is represented by the following structure:
.Bd -literal -offset indent
struct cdecl {
struct cdecl *next;
.Va specifiers
and
.Va declarators
-members are always non-null. A declaration with more than one declarator is
-represented by using the
+members are always non-null.
+A declaration with more than one declarator is represented by using the
.Va next
member to form a singly-linked list of ASTs, one element for each declarator.
In the case of the toplevel declaration, the declaration specifiers will be
-identical for all elements of the list. But when the same kind of list is used
-to represent function parameters, the specifiers may be different for each
-element.
+identical for all elements of the list.
+But when the same kind of list is used to represent function parameters, the
+specifiers may be different for each element.
.Pp
There are four kinds of declaration specifiers: storage-class, function and
-type specifiers, as well as type qualifiers. All are represented by the
-structure:
+type specifiers, as well as type qualifiers.
+All are represented by the structure:
.Bd -literal -offset indent
struct cdecl_declspec {
struct cdecl_declspec *next;
.Ed
.Pp
When multiple declaration specifiers are present, they are represented as
-a singly-linked list, one element for each specifier. Specifiers can appear
-in any order. The function
+a singly-linked list, one element for each specifier.
+Specifiers can appear in any order.
+The function
.Pp
.Fd int cdecl_spec_kind(struct cdecl_declspec *spec);
.Pp
is. The result is one of the following values:
.Bl -column ".Dv CDECL_SPEC_TYPE"
.It Em Kind Ta Em Description
-.It Dv CDECL_SPEC_TYPE Ta Type specifier.
-.It Dv CDECL_SPEC_STOR Ta Storage-class specifier.
-.It Dv CDECL_SPEC_QUAL Ta Type qualifier.
-.It Dv CDECL_SPEC_FUNC Ta Function specifier.
+.It Dv CDECL_SPEC_TYPE Ta Type specifier .
+.It Dv CDECL_SPEC_STOR Ta Storage-class specifier .
+.It Dv CDECL_SPEC_QUAL Ta Type qualifier .
+.It Dv CDECL_SPEC_FUNC Ta Function specifier .
.El
.Pp
-The following table describes all the possible types of declaration specifiers.
+The following table describes all the possible types of declaration specifiers:
.Bl -column ".Dv CDECL_TYPE_IMAGINARY"
.It Em Em Type Ta Em Description
-.It Dv CDECL_TYPE_VOID Ta Fa void No type specifier.
-.It Dv CDECL_TYPE_CHAR Ta Fa char No type specifier.
-.It Dv CDECL_TYPE_SHORT Ta Fa short No type specifier.
-.It Dv CDECL_TYPE_INT Ta Fa int No type specifier.
-.It Dv CDECL_TYPE_LONG Ta Fa long No type specifier.
-.It Dv CDECL_TYPE_FLOAT Ta Fa float No type specifier.
-.It Dv CDECL_TYPE_DOUBLE Ta Fa double No type specifier.
-.It Dv CDECL_TYPE_SIGNED Ta Fa signed No type specifier.
-.It Dv CDECL_TYPE_UNSIGNED Ta Fa unsigned No type specifier.
-.It Dv CDECL_TYPE_BOOL Ta Fa _Bool No type specifier.
-.It Dv CDECL_TYPE_COMPLEX Ta Fa _Comples No type specifier.
-.It Dv CDECL_TYPE_IMAGINARY Ta Fa _Imaginary No type specifier.
-.It Dv CDECL_TYPE_STRUCT Ta Fa struct No type specifier. The
+.It Dv CDECL_TYPE_VOID Ta Fa void No type specifier .
+.It Dv CDECL_TYPE_CHAR Ta Fa char No type specifier .
+.It Dv CDECL_TYPE_SHORT Ta Fa short No type specifier .
+.It Dv CDECL_TYPE_INT Ta Fa int No type specifier .
+.It Dv CDECL_TYPE_LONG Ta Fa long No type specifier .
+.It Dv CDECL_TYPE_FLOAT Ta Fa float No type specifier .
+.It Dv CDECL_TYPE_DOUBLE Ta Fa double No type specifier .
+.It Dv CDECL_TYPE_SIGNED Ta Fa signed No type specifier .
+.It Dv CDECL_TYPE_UNSIGNED Ta Fa unsigned No type specifier .
+.It Dv CDECL_TYPE_BOOL Ta Fa _Bool No type specifier .
+.It Dv CDECL_TYPE_COMPLEX Ta Fa _Comples No type specifier .
+.It Dv CDECL_TYPE_IMAGINARY Ta Fa _Imaginary No type specifier .
+.It Dv CDECL_TYPE_STRUCT Ta Fa struct No type specifier .
+The
.Va ident
member points to a C string containing the struct tag.
-.It Dv CDECL_TYPE_UNION Ta Fa union No type specifier. The
+.It Dv CDECL_TYPE_UNION Ta Fa union No type specifier .
+The
.Va ident
member points to a C string containing the union tag.
-.It Dv CDECL_TYPE_ENUM Ta Fa enum No type specifier. The
+.It Dv CDECL_TYPE_ENUM Ta Fa enum No type specifier .
+The
.Va ident
member points to a C string containing the enum tag.
-.It Dv CDECL_TYPE_IDENT Ta Typedef name type specifier. The
+.It Dv CDECL_TYPE_IDENT Ta Typedef name type specifier .
+The
.Va ident
member points to a C string containing the identifier.
-.It Dv CDECL_STOR_TYPEDEF Ta Fa typedef No storage-class specifier.
-.It Dv CDECL_STOR_EXTERN Ta Fa extern No storage-class specifier.
-.It Dv CDECL_STOR_STATIC Ta Fa static No storage-class specifier.
-.It Dv CDECL_STOR_AUTO Ta Fa auto No storage-class specifier.
-.It Dv CDECL_STOR_REGISTER Ta Fa register No storage-class specifier.
-.It Dv CDECL_QUAL_RESTRICT Ta Fa restrict No type qualifier.
-.It Dv CDECL_QUAL_VOLATILE Ta Fa volatile No type qualifier.
-.It Dv CDECL_QUAL_CONST Ta Fa const No type qualifier.
-.It Dv CDECL_FUNC_INLINE Ta Fa inline No function specifier.
+.It Dv CDECL_STOR_TYPEDEF Ta Fa typedef No storage-class specifier .
+.It Dv CDECL_STOR_EXTERN Ta Fa extern No storage-class specifier .
+.It Dv CDECL_STOR_STATIC Ta Fa static No storage-class specifier .
+.It Dv CDECL_STOR_AUTO Ta Fa auto No storage-class specifier .
+.It Dv CDECL_STOR_REGISTER Ta Fa register No storage-class specifier .
+.It Dv CDECL_QUAL_RESTRICT Ta Fa restrict No type qualifier .
+.It Dv CDECL_QUAL_VOLATILE Ta Fa volatile No type qualifier .
+.It Dv CDECL_QUAL_CONST Ta Fa const No type qualifier .
+.It Dv CDECL_FUNC_INLINE Ta Fa inline No function specifier .
.El
.Pp
Declarators are represented by the structure:
With the exception of function parameters (which are handled separately),
declarators form a chain from
.Do outermost Dc to Do innermost Dc
-declarator. This relationship is expressed by the
+declarator.
+This relationship is expressed by the
.Va child
struct member, which points to the next innermost declarator in the chain.
-Unfortunately, C's declaration syntax is, in a sense, inside-out. Thus, one
-needs to follow the chain backwards (from innermost to outermost) to understand
-the semantic relationship between declarators in the chain. In the next
-section, we will use the word
+Unfortunately, C's declaration syntax is, in a sense, inside-out.
+Thus, one needs to follow the chain backwards (from innermost to outermost) to
+understand the semantic relationship between declarators in the chain.
+In the next section, we will use the word
.Va parent
to describe this inverted child relationship: we consider the outermost
declarator's
as the declaration's base type (found amongst the declaration specifiers, e.g.
.Li int , const unsigned long ,
etc.)
-
+.Pp
The five types of declarators, described below, are distinguished by the
.Va type
-struct member. Each declarator (except null declarators) carries additional
-information specific to its type, which corresponds to the members of the union
+struct member.
+Each declarator (except null declarators) carries additional information
+specific to its type, which corresponds to the members of the union
.Va u .
-
-contains a member for each declarator type (except null) containing additional
-information. The possible values are described by the following table.
+The possible values are described by the following table:
.Bl -column ".Dv CDECL_DECL_FUNCTION" ".Em Union Member"
.It Em Declarator Type Ta Em Union Member Ta Em Description
.It Dv CDECL_DECL_NULL Ta (none) Ta Declares nothing. This
.Do function returning Va parent Dc
.El
.Ss Terminal Declarators
-Null and identifier declarators have no children and are thus leaf nodes. A
-null declarator is not strictly a C language construct, but is used by
+Null and identifier declarators have no children and are thus leaf nodes.
+A null declarator is not strictly a C language construct, but is used by
.Nm
to indicate an abstract declarator; that is, one which does not declare any
-identifier. Such declarators appear in type names and possibly function
-parameters. An identifier declarator has the obvious meaning; the
+identifier.
+Such declarators appear in type names and possibly function parameters.
+An identifier declarator has the obvious meaning; the
.Va ident
union member points to the C string containing the identifier.
.Pp
.Fd bool cdecl_is_abstract(struct cdecl_declarator *declarator);
.Pp
can be used to determine whether or not a given declarator declares an
-identifier. The result is true if and only if the declarator is abstract.
+identifier.
+The result is true if and only if the declarator is abstract.
.Ss Pointer Declarators
.Bd -literal -offset indent
struct cdecl_pointer {
.Pp
If
.Va parameters
-is null, then this is a non-prototype function declarator. Otherwise,
+is null, then this is a non-prototype function declarator.
+Otherwise,
.Va parameters
points to the first element of a singly-linked list of declarations
-representing the function parameters. Note that, unlike toplevel declarations,
-each function parameter has exactly one full declarator (abstract or
-otherwise). If
+representing the function parameters.
+Note that, unlike toplevel declarations, each function parameter has exactly
+one full declarator (abstract or otherwise).
+If
.Va variadic
is true, then the function is variadic.
.Pp
Note that old-style function declarations with non-empty identifier lists are
not directly represented here: this is because they are syntactically identical
-to a prototype where every parameter is a typedef name. Since
+to a prototype where every parameter is a typedef name.
+Since
.Nm
-isn't a C compiler, there is no way for the parser to tell these two kinds of
+isn't a C compiler, there is no way for its parser to tell these two kinds of
declarations apart.
.Sh ERROR HANDLING
Some functions in
.Nm
-can fail. Such functions will be documented as indicating an error condition
-in a particular way. It is sometimes necessary to know more about a particular
-error in order to print an informative error message or perform some other
-action. To facilitate this,
+can fail.
+Such functions will be documented as indicating an error condition in a
+particular way.
+It is sometimes necessary to know more about a particular error in order to
+print an informative error message or perform some other action.
+To facilitate this,
.Nm
provides a structure which describes a particular error.
.Bd -literal -offset indent
.Fd const struct cdecl_error *cdecl_get_error(void);
.Pp
which returns a pointer to the error structure most recently generated in the
-current thread. It is therefore thread-safe in that errors occurring in
-another thread will not interfere with the current one. The returned pointer
-shall remain valid until the next call to any function from
+current thread.
+It is therefore thread-safe in that errors occurring in another thread will not
+interfere with the current one.
+The returned pointer shall remain valid until the next call to any function
+from
.Nm
by the same thread, except that multiple consecutive calls to
.Va cdecl_get_error
-shall all return the same value. The same applies to the
+shall all return the same value.
+The same applies to the
.Va str
pointer inside the error structure itself.
.Pp
.Pp
.Fd struct cdecl *cdecl_parse_decl(const char *declstr);
.Pp
-can be used. The provided string is parsed as a C declaration. If successful,
-this function returns a pointer to an abstract syntax tree representing the
-declaration. If the parse fails for any reason, the function returns NULL.
+can be used.
+The provided string is parsed as a C declaration.
+If successful, this function returns a pointer to an abstract syntax tree
+representing the declaration.
+If the parse fails for any reason, the function returns NULL.
.Pp
Similarly, English declarations can be parsed by using the function
.Pp
.Pp
.Fd void cdecl_free(struct cdecl *decl);
.Sh RENDERING DECLARATIONS
-On the other hand, the abstract syntax tree can be rendered to a string for
-output. One can use the function
+After parsing, the abstract syntax tree can be rendered to a string for output.
+Use the function
.Pp
.Fd size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl);
.Pp
to format the AST pointed to by
.Fa decl
-into something resembling English. At most one full declarator is rendered
-in this way; for declarations with more than one full declarator, this function
-should be called on each
+into something resembling English.
+At most one full declarator is rendered in this way; for declarations with more
+than one full declarator, this function should be called on each
.Dv struct cdecl
in the singly-linked list.
.Pp
.Fa n
is zero, it is acceptable for
.Fa buf
-to be a null pointer. Regardless, the function returns the number of
-characters that would be written to
+to be a null pointer.
+Regardless, the function returns the number of characters that would be written
+to
.Fa buf
if
.Fa n
-were long enough, not including the '\\0' terminator. Thus, the entire string
-was written if a value less than
+were long enough, not including the '\\0' terminator.
+Thus, the entire string was written if a value less than
.Fa n
is returned.
.Pp
.Sh AUTHORS
Nick Bowler <nbowler@draconx.ca>
.Sh COPYRIGHT
-Copyright \(co 2011 Nick Bowler
+Copyright \(co 2011\(en2012, 2021 Nick Bowler
.Pp
Permission is granted to copy, distribute and/or modify this manual under the
-terms of the Do What The Fuck You Want To Public License, version 2.
+terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
.Sh SEE ALSO
.Xr cdecl99 1