and is described by the following context-free grammar. This grammar is for
illustrative purposes only: it is ambiguous and doesn't capture all the nuances
of the C language. In this grammar, nonterminals are represented
-.Fa thusly ,
+.Va thusly ,
\[*e] represents the empty string, and both
.Li |
and successive \[->] under the same nonterminal indicate alternation. All
other symbols are terminals. The nonterminals
-.Fa identifier , type-specifier , type-qualifier , storage-class-specifier
+.Va identifier , type-specifier , type-qualifier , storage-class-specifier
and
-.Fa function-specifier
+.Va function-specifier
are defined as in C.
-.Bl -column -offset indent ".Fa english-decl" ""
-.It Fa english Ta \[->] Ta Li declare Fa identifier Li as Fa english-decl
-.It Ta \[->] Ta Li type Fa english-decl
-.It Fa english-decl Ta \[->] Ta Fa sf-specs declarator
-.It Fa declarator Ta \[->] Ta Fa qualifiers Li pointer to Fa declarator
-.It Ta \[->] Ta Li array Fa size Li of Fa declarator
-.It Ta \[->] Ta Li function Fa parameters Li returning Fa declarator
-.It Ta \[->] Ta Fa tq-specs
-.It Fa qualifiers Ta \[->] Ta Fa type-qualifier qualifiers | No \[*e]
-.It Fa tq-specs Ta \[->] Ta Fa type-qualifier tq-specs
-.It Ta \[->] Ta Fa type-specifier tq-specs
+.Bl -column -offset indent ".Va english-decl" ""
+.It Va english Ta \[->] Ta Li declare Va identifier Li as Va english-decl
+.It Ta \[->] Ta Li type Va english-decl
+.It Va english-decl Ta \[->] Ta Va sf-specs declarator
+.It Va declarator Ta \[->] Ta Va qualifiers Li pointer to Va declarator
+.It Ta \[->] Ta Li array Va size Li of Va declarator
+.It Ta \[->] Ta Li function Va parameters Li returning Va declarator
+.It Ta \[->] Ta Va tq-specs
+.It Va qualifiers Ta \[->] Ta Va type-qualifier qualifiers | No \[*e]
+.It Va tq-specs Ta \[->] Ta Va type-qualifier tq-specs
+.It Ta \[->] Ta Va type-specifier tq-specs
.It Ta \[->] Ta \[*e]
-.It Fa sf-specs Ta \[->] Ta Fa storage-class-specifier sf-specs
-.It Ta \[->] Ta Fa function-specifier sf-specs
+.It Va sf-specs Ta \[->] Ta Va storage-class-specifier sf-specs
+.It Ta \[->] Ta Va function-specifier sf-specs
.It Ta \[->] Ta \[*e]
-.It Fa size Ta \[->] Ta Fa integer | Fa identifier | Li * | No \[*e]
-.It Fa parameters Ta \[->] Ta Po Fa param-list Pc
-.It Ta \[->] Ta Po Fa param-list Li , ... Pc
+.It Va size Ta \[->] Ta Va integer | Va identifier | Li * | No \[*e]
+.It Va parameters Ta \[->] Ta Po Va param-list Pc
+.It Ta \[->] Ta Po Va param-list Li , ... Pc
.It Ta \[->] Ta \[*e]
-.It Fa param-list Ta \[->] Ta Fa parameter | Fa parameter Li , Fa param-list
-.It Fa parameter Ta \[->] Ta Fa identifier Li as Fa english-decl
-.It Ta \[->] Ta Fa english-decl
+.It Va param-list Ta \[->] Ta Va parameter | Va parameter Li , Va param-list
+.It Va parameter Ta \[->] Ta Va identifier Li as Va english-decl
+.It Ta \[->] Ta Va english-decl
.El
.Sh RESOLVING AMBIGUITIES
The C context-free grammar has many ambiguities regarding declarations.
For example, the meaning of the declaration
.Ic int f(int (foo))
depends on whether or not a typedef named
-.Fa foo
+.Va foo
is in scope. If such a typedef is in scope, this declares
-.Fa f
+.Va f
as a function that takes (after adjustment) a pointer to a function that takes
a
-.Fa foo
+.Va foo
and returns an int, returning an int. If there is no such typedef, then this
declares
-.Fa f
+.Va f
as a function that takes an int and returns an int.
Since
At the top level, every declaration consists of one or more declaration
specifiers followed by one or more full declarators; hence, the
-.Fa specifiers
+.Va specifiers
and
-.Fa declarators
+.Va declarators
members are always non-null. A declaration with more than one declarator is
represented by using the
-.Fa next
+.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
.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
+.Va 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
+.Va 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
+.Va ident
member points to a C string containing the enum tag.
.It Dv CDECL_TYPE_IDENT Ta Typedef name type specifier. The
-.Fa ident
+.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.
.Ed
There are five types of declarators, distinguished by the
-.Fa type
+.Va type
struct member. The union
.u
contains a member for each declarator type (except null) containing additional
.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
+.Va child .
+.It Dv CDECL_DECL_IDENT Ta Va 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
+.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 Fa array Ta Declares an array. The
-.Fa 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 Fa function Ta Declares a function. The
-.Fa child
+.It Dv CDECL_DECL_FUNCTION Ta Va function Ta Declares a function. The
+.Va child
member is interpreted as "function returning child".
.El
.Ss Terminal Declarators
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
+.Va ident
union member points to the C string containing the identifier.
.Ss Pointer Declarators
.Bd -literal -offset indent
.Ed
If the
-.Fa qualifiers
+.Va qualifiers
member is non-null, then it points to the first element of a singly-linked list
of type qualifiers.
.Ss Array Declarators
.Ed
If the
-.Fa vla
+.Va vla
member is non-null, then this declarator is a variable-length array declarator.
The
-.Fa vla
+.Va vla
member points to an identifier if it is known, else it points to the empty
string.
Otherwise, if
-.Fa length
+.Va length
is positive, then this is an array declarator with the specified length.
Otherwise, this is an incomplete array declarator.
.Ss Function Declarators
.Ed
If
-.Fa parameters
+.Va parameters
is null, then this is a non-prototype function declarator. Otherwise,
-.Fa parameters
+.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
-.Fa variadic
+.Va variadic
is true, then the function is variadic.
.Sh PARSING DECLARATIONS
To parse a declaration, the function