]> git.draconx.ca Git - cdecl99.git/blobdiff - doc/libcdecl.3
Minor manual updates.
[cdecl99.git] / doc / libcdecl.3
diff --git a/doc/libcdecl.3 b/doc/libcdecl.3
new file mode 100644 (file)
index 0000000..495a353
--- /dev/null
@@ -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 <cdecl.h>
+.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 <nbowler@draconx.ca>
+.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