+.Dd July 18, 2011
+.Os cdecl99
+.Dt LIBCDECL \&3 "Cdecl99 Developer's Manual"
+.Sh NAME
+.Nm libcdecl
+.Nd C library for making sense of C declarations
+.Sh SYNOPSIS
+.Fd #include <cdecl.h>
+
+.Fd struct cdecl *cdecl_parse_decl(const char *declstr);
+.Fd struct cdecl *cdecl_parse_english(const char *english);
+.Fd void cdecl_free(struct cdecl *decl);
+
+.Fd size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl);
+.Fd size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl);
+
+.Fd int cdecl_spec_kind(struct cdecl_declspec *spec);
+.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
+.Xr cdecl99 1
+manual page.
+
+.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 maintains no global state
+and thus all functions should be safe for use in a multi-threaded environment.
+.Sh ABSTRACT SYNTAX TREE
+The functions in
+.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:
+.Bd -literal -offset indent
+struct cdecl {
+ struct cdecl *next;
+ struct cdecl_declspec *specifiers;
+ struct cdecl_declarator *declarators;
+};
+.Ed
+
+At the top level, every declaration consists of one or more declaration
+specifiers followed by one or more full declarators; hence, the
+.Fa specifiers
+and
+.Fa declarators
+members are always non-null. A declaration with more than one declarator is
+represented by using the
+.Fa 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.
+
+There are four kinds of declaration specifiers: storage-class, function and
+type specifiers, as well as type qualifiers. All are represented by the
+structure:
+.Bd -literal -offset indent
+struct cdecl_declspec {
+ struct cdecl_declspec *next;
+ unsigned type;
+ char *ident;
+};
+.Ed
+
+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
+
+.Fd int cdecl_spec_kind(struct cdecl_declspec *spec);
+
+can be used to determine what kind of specifier
+.Fa spec
+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.
+.El
+
+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
+.Fa ident
+member points to a C string containing the struct tag.
+.It Dv CDECL_TYPE_UNION Ta Fa union No type specifier. The
+.Fa ident
+member points to a C string containing the union tag.
+.It Dv CDECL_TYPE_ENUM Ta Fa enum No type specifier. The
+.Fa ident
+member points to a C string containing the enum tag.
+.It Dv CDECL_TYPE_IDENT Ta Typedef name type specifier. The
+.Fa 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.
+.El
+
+Declarators are represented by the structure:
+.Bd -literal -offset indent
+struct cdecl_declarator {
+ struct cdecl_declarator *child;
+ unsigned type;
+ union {
+ char *ident;
+ struct cdecl_pointer pointer;
+ struct cdecl_array array;
+ struct cdecl_function function;
+ } u;
+};
+.Ed
+
+There are five types of declarators, distinguished by the
+.Fa type
+struct member. The union
+.u
+contains a member for each declarator type (except null) containing additional
+information. The possible values are described by the following table. The
+description of the child member is a lie.
+.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
+declarator has no
+.Fa child .
+.It Dv CDECL_DECL_IDENT Ta Fa ident Ta Declares an identifier. This
+declarator has no
+.Fa child .
+.It Dv CDECL_DECL_POINTER Ta Fa pointer Ta Declares a pointer. The
+.Fa child
+member is interpreted as "pointer to child".
+.It Dv CDECL_DECL_ARRAY Ta Fa array Ta Declares an array. The
+.Fa child
+member is interpreted as "array of child".
+.It Dv CDECL_DECL_FUNCTION Ta Fa function Ta Declares a function. The
+.Fa child
+member is interpreted as "function returning child".
+.El
+.Ss Terminal Declarators
+Null and identifier declarators have no children and are thus leaf nodes. A
+null declarator indicates 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
+.Fa ident
+union member points to the C string containing the identifier.
+.Ss Pointer Declarators
+.Bd -literal -offset indent
+struct cdecl_pointer {
+ struct cdecl_declspec *qualifiers;
+};
+.Ed
+
+If the
+.Fa qualifiers
+member is non-null, then it points to the first element of a singly-linked list
+of type qualifiers.
+.Ss Array Declarators
+.Bd -literal -offset indent
+struct cdecl_array {
+ char *vla;
+ uintmax_t length;
+};
+.Ed
+
+If the
+.Fa vla
+member is non-null, then this declarator is a variable-length array declarator.
+The
+.Fa vla
+member points to an identifier if it is known, else it points to the empty
+string.
+Otherwise, if
+.Fa length
+is positive, then this is an array declarator with the specified length.
+Otherwise, this is an incomplete array declarator.
+.Ss Function Declarators
+.Bd -literal -offset indent
+struct cdecl_function {
+ struct cdecl *parameters;
+ _Bool variadic;
+};
+.Ed
+
+If
+.Fa parameters
+is null, then this is a non-prototype function declarator. Otherwise,
+.Fa 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
+.Fa variadic
+is true, then the function is variadic.
+.Sh PARSING DECLARATIONS
+To parse a declaration, the function
+
+.Fd struct cdecl *cdecl_parse_decl(const char *declstr);
+
+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.
+
+Similarly, English declarations can be parsed by using the function
+
+.Fd struct cdecl *cdecl_parse_english(const char *english);
+
+When the AST is no longer needed, it must be freed by passing it to the
+function
+
+.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
+
+.Fd size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl);
+
+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
+.Dv struct cdecl
+in the singly-linked list.
+
+In a manner similar to that of
+.Xr snprintf 3 ,
+at most
+.Fa n
+bytes, including the '\\0' terminator, are written to
+.Fa buf .
+If
+.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
+.Fa buf
+if
+.Fa n
+were long enough, not including the '\\0' terminator. Thus, the entire string
+was written if a value less than
+.Fa n
+is returned.
+
+Similarly, the function
+
+.Fd size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl);
+
+will render the AST pointed to by
+.Fa decl
+into C code.
+.Sh AUTHORS
+Nick Bowler <nbowler@draconx.ca>
+.Sh COPYRIGHT
+Copyright \(co 2011 Nick Bowler
+
+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.
+.Sh SEE ALSO
+.Xr cdecl99 1