mirror of
https://gitlab.com/fbb-git/cppannotations
synced 2024-11-16 07:48:44 +01:00
130 lines
7.2 KiB
Text
130 lines
7.2 KiB
Text
The i(declaration section) contains several sets of declarations, among
|
|
which definitions of all the tokens used in the grammar and the priorities and
|
|
associativities of the mathematical operators. Moreover, several new and
|
|
important specifications can be used here as well. Those relevant to our
|
|
current example and only available in tt(bisonc++) are discussed here. The
|
|
reader is referred to tt(bisonc++)'s man-page for a full description.
|
|
itemization(
|
|
it() bi(%baseclass-preinclude) tt(header)nl()
|
|
Use tt(header) as the pathname to the file pre-included in the
|
|
parser's base-class header. This declaration is useful in
|
|
situations where the base class header file refers to types which
|
|
might not yet be known. E.g., with ti(%union) a tt(std::string *)
|
|
field might be used. Since the class tt(std::string) might not yet
|
|
be known to the compiler once it processes the base class header
|
|
file we need a way to inform the compiler about these classes and
|
|
types. The suggested procedure is to use a pre-include header file
|
|
declaring the required types. By default tt(header) is
|
|
surrounded by double quotes (using, e.g., tt(#include "header")).
|
|
When the argument is surrounded by angle brackets tt(#include
|
|
<header>) is included. In the latter case, quotes might be
|
|
required to escape interpretation by the shell (e.g., using tt(-H
|
|
'<header>')).
|
|
it() bi(%filenames) tt(header) nl()
|
|
Defines the generic name of all generated files, unless overridden
|
|
by specific names. By default the generated files use the
|
|
class-name as the generic file name.
|
|
it() bi(%scanner) tt(header)nl()
|
|
Use tt(header) as the pathname to the file pre-included in the
|
|
parser's class header. This file should define a class
|
|
tt(Scanner), offering a member tt(int lex()) producing the next
|
|
token from the input stream to be analyzed by the parser generated
|
|
by tt(bisonc++). When this option is used the parser's member
|
|
tt(int lex()) is predefined as (assuming the default parser class
|
|
name tt(Parser) is used):
|
|
verb(
|
|
inline int Parser::lex()
|
|
{
|
|
return d_scanner.lex();
|
|
}
|
|
)
|
|
and an object tt(Scanner d_scanner) is composed into the
|
|
parser. The tt(d_scanner) object is constructed by its
|
|
default constructor. If another constructor is required, the
|
|
parser class may be provided with an appropriate (overloaded)
|
|
parser constructor after having constructed the default parser
|
|
class header file using tt(bisonc++). By default tt(header) is
|
|
surrounded by double quotes (using, e.g., tt(#include
|
|
"header")). When the argument is surrounded by angle brackets
|
|
tt(#include <header>) is included.
|
|
it() bi(%stype) tt(typename) nl()
|
|
The type of the semantic value of tokens. The specification
|
|
tt(typename) should be the name of an unstructured type (e.g.,
|
|
tt(size_t)). By default it is tt(int). See tt(YYSTYPE) in
|
|
tt(bison). It should not be used if a tt(%union) specification is
|
|
used. Within the parser class, this type may be used as
|
|
tt(STYPE).
|
|
it() bi(%union) tt(union-definition) nl()
|
|
Acts identically to the tt(bison) declaration. As with tt(bison)
|
|
this generates a union for the parser's semantic type. The union
|
|
type is named tt(STYPE). If no tt(%union) is declared, a simple
|
|
stack-type may be defined using the tt(%stype) declaration. If no
|
|
tt(%stype) declaration is used, the default stacktype (tt(int)) is
|
|
used.
|
|
)
|
|
An example of a tt(%union) declaration is:
|
|
verb(
|
|
%union
|
|
{
|
|
int i;
|
|
double d;
|
|
};
|
|
)
|
|
In pre-C++11 code a i(union) cannot contain objects as its fields, as
|
|
constructors cannot be called when a union is created. This means that
|
|
hi(string: as union member) a tt(string) cannot be a member of the
|
|
union. A tt(string *), however, em(is) a possible union member. It might also
|
|
be possible to use em(unrestricted unions) (cf. section ref(UNIONS)), having
|
|
class type objects as fields.
|
|
|
|
As an aside: the scanner does not have to know about such a union. It
|
|
can simply pass its scanned text to the parser through its ti(matched) member
|
|
function. For example using a statement like
|
|
verb(
|
|
$$.i = A2x(d_scanner.matched());
|
|
)
|
|
matched text is converted to a value of an appropriate type.
|
|
|
|
Tokens and non-terminals can be associated with union fields. This is
|
|
strongly advised, as it prevents type mismatches, since the compiler may then
|
|
check for type correctness. At the same time, the bison specific
|
|
variables tt($$), tt($1), tt($2), etc. may be used, rather than the full field
|
|
specification (like tt($$.i)). A non-terminal or a token may be associated
|
|
with a union field using the
|
|
tt(<fieldname>) specification. E.g.,
|
|
verb(
|
|
%token <i> INT // token association (deprecated, see below)
|
|
<d> DOUBLE
|
|
%type <i> intExpr // non-terminal association
|
|
)
|
|
In the example developed here, both the tokens and the non-terminals can
|
|
be associated with a union field. However, as noted before, the scanner does
|
|
not have to know about all this. In our opinion, it is cleaner to let the
|
|
scanner do just one thing: scan texts. The em(parser), knowing what the input
|
|
is all about, may then convert strings like tt("123") to an integer
|
|
value. Consequently, the association of a union field and a token is
|
|
discouraged. Below, while describing the grammar's rules, this is further
|
|
illustrated.
|
|
|
|
In the tt(%union) discussion the ti(%token) and ti(%type) specifications
|
|
should be noted. They are used to specify the tokens (terminal symbols) that
|
|
can be returned by the scanner, and to specify the return types of
|
|
non-terminals. Apart from tt(%token) the token declarators ti(%left),
|
|
ti(%right), and ti(%nonassoc) can be used to specify the associativity of
|
|
operators. The tokens mentioned at these indicators are interpreted as tokens
|
|
indicating operators, associating in the indicated direction. The precedence
|
|
of operators is defined by their order: the first specification has the lowest
|
|
priority. To overrule a certain precedence in a certain context ti(%prec) can
|
|
be used. As all this is standard tt(bisonc++) practice, it isn't further
|
|
elaborated here. The documentation provided with tt(bisonc++)'s distribution
|
|
should be consulted for further reference.
|
|
|
|
Here is the specification of the calculator's declaration section:
|
|
verbinclude(//DECLARATION bisonc++/parser/grammar)
|
|
In the declaration section tt(%type) specifiers are used, associating the
|
|
tt(intExpr) rule's value (see the next section) to the tt(i)-field of the
|
|
semantic-value union, and associating tt(doubleExpr)'s value to the
|
|
tt(d)-field. This approach, admittedly, is rather complex, as expression rules
|
|
must be included for each of the supported union types. Alternatives are
|
|
definitely possible, and are illustrated in subsequent sections (e.g., section
|
|
ref(BISONSEM)).
|