X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/41e93dfe1f8302927246aa8802b57d46c996703c..519f8a57b1353d595b3e6e9aa0ff50eaffb164ca:/doc/libcdecl.3 diff --git a/doc/libcdecl.3 b/doc/libcdecl.3 new file mode 100644 index 0000000..495a353 --- /dev/null +++ b/doc/libcdecl.3 @@ -0,0 +1,410 @@ +.Dd March 6, 2021 +.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 +.Pp +.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); +.Pp +.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 +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. +.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 +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 +.Pp +At the top level, every declaration consists of one or more declaration +specifiers followed by one or more full declarators; hence, the +.Va specifiers +and +.Va declarators +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. +.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: +.Bd -literal -offset indent +struct cdecl_declspec { + struct cdecl_declspec *next; + unsigned type; + char *ident; +}; +.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 +.Pp +.Fd int cdecl_spec_kind(struct cdecl_declspec *spec); +.Pp +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 +.Pp +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 +.Va ident +member points to a C string containing the struct tag. +.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 +.Va ident +member points to a C string containing the enum tag. +.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 . +.El +.Pp +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 +.Pp +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.) +.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 +.Va u . +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 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 a NULL +.Va 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 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 { + struct cdecl_declspec *qualifiers; +}; +.Ed +.Pp +If the +.Va 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 +.Pp +If the +.Va vla +member is non-null, then this declarator is a variable-length array declarator. +The +.Va vla +member points to an identifier if it is known, else it points to the empty +string. +Otherwise, if +.Va 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 +.Pp +If +.Va parameters +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 +.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 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, +.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 +.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. +.Pp +Similarly, English declarations can be parsed by using the function +.Pp +.Fd struct cdecl *cdecl_parse_english(const char *english); +.Pp +When the AST is no longer needed, it must be freed by passing it to the +function +.Pp +.Fd void cdecl_free(struct cdecl *decl); +.Sh RENDERING DECLARATIONS +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 +.Dv struct cdecl +in the singly-linked list. +.Pp +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. +.Pp +Similarly, the function +.Pp +.Fd size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl); +.Pp +will render the AST pointed to by +.Fa decl +into C code. +.Sh AUTHORS +Nick Bowler +.Sh COPYRIGHT +Copyright \(co 2011\(en2012, 2021 Nick Bowler +.Pp +Permission is granted to copy, distribute and/or modify this manual under the +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