.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);
.Pp
+.Fd const struct cdecl_error *cdecl_get_error(void);
+.Pp
.Fd int cdecl_spec_kind(struct cdecl_declspec *spec);
+.Fd bool cdecl_is_abstract(struct cdecl_declarator *declarator);
.Sh DESCRIPTION
.Nm
provides support for parsing C declarations and translating them to something
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.
+.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
+.Li cdecl_
+are reserved, and the library headers may define object-like macros beginning
+with
+.Li CDECL_ .
+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.
+.Pp
+External names beginning with
+.Li cdecl
+followed by two consecutive underscores are not considered part of the ABI and
+are thus subject to change at any time.
.Sh ABSTRACT SYNTAX TREE
The functions in
.Nm
};
.Ed
.Pp
-There are five types of declarators, distinguished by the
+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
+.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
+.Va parent
+to describe this inverted child relationship: we consider the outermost
+declarator's
+.Va parent
+as the declaration's base type (found amongst the declaration specifiers, e.g.
+.Li int , const unsigned long ,
+etc.)
+
+The five types of declarators, described below, are distinguished by the
.Va type
-struct member. The union
-.u
+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
-description of the child member is a lie.
+information. 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
-declarator has no
+declarator terminates the declarator chain, and has a NULL
.Va child .
.It Dv CDECL_DECL_IDENT Ta Va ident Ta Declares an identifier. This
-declarator has no
+declarator has a NULL
.Va child .
-.It Dv CDECL_DECL_POINTER Ta Va pointer Ta Declares a pointer. The
-.Va child
-member is interpreted as "pointer to child".
-.It Dv CDECL_DECL_ARRAY Ta Va array Ta Declares an array. The
-.Va child
-member is interpreted as "array of child".
-.It Dv CDECL_DECL_FUNCTION Ta Va function Ta Declares a function. The
-.Va child
-member is interpreted as "function returning child".
+.It Dv CDECL_DECL_POINTER Ta Va pointer Ta Declares a pointer, as in
+.Do pointer to Va parent Dc
+.It Dv CDECL_DECL_ARRAY Ta Va array Ta Declares an array, as in
+.Do array of Va parent Dc
+.It Dv CDECL_DECL_FUNCTION Ta Va function Ta Declares a function, as in
+.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 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
+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
.Va ident
union member points to the C string containing the identifier.
+.Pp
+Since a null declarator may be deeply nested in the declarator chain, the
+function
+.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.
.Ss Pointer Declarators
.Bd -literal -offset indent
struct cdecl_pointer {
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
+.Nm
+isn't a C compiler, there is no way for the 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,
+.Nm
+provides a structure which describes a particular error.
+.Bd -literal -offset indent
+struct cdecl_error {
+ unsigned code;
+ const char *str;
+};
+.Ed
+.Pp
+The
+.Va code
+member identifies the sort of error which has occurred, while the
+.Va str
+member points to a string containing a human-readable description of the error.
+This error information can be retrieved by calling the function
+.Pp
+.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
+.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
+.Va str
+pointer inside the error structure itself.
+.Pp
+If this function is called before an error has been indicated by an earlier
+call in the same thread, the behaviour is undefined.
.Sh PARSING DECLARATIONS
To parse a declaration, the function
.Pp