1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
As noted in the previous section, Bisonc++'s grammar specification declares
tt(%stype), the semantic value type, as tt(spSembase). A simple grammar is
defined for this illustrative example. The grammar expects input according to
the following rule:
verb( rule:
IDENTIFIER '(' IDENTIFIER ')' ';'
|
IDENTIFIER '=' INT ';'
;)
The rule's actions simply echo the received identifiers and tt(int) values to
tt(cout). Here is an example of a decorated production rule, where due to
tt(Semantic)'s overloaded insertion operator the insertion of the object
controlled by tt(Semantic) is automatically performed:
verb( IDENTIFIER '=' INT ';'
{
cout << $1 << " " << $3 << '\n';
})
Bisonc++'s parser stores em(all) semantic values on its semantic values stack
(irrespective of the number of tokens that were defined in a particular
production rule). At any time em(all) semantic values associated with
previously recognized tokens are available in an action block. Once the
semantic value stack is reduced, the tt(Semantic) class's destructor takes
care of the proper destruction of the objects controlled by its tt(shared_ptr)
base class.
In order to assign the parser's latest semantic value, the scanner is given
access to that data member, which is the parser's data member tt(d_val__). Its
address or reference can be passed to the scanner when it is
constructed. E.g., if the scanner's constructor expects an tt(STYPE__ &)
argument, then the parser's constructor could simply be implemented as:
verb( inline Parser::Parser()
:
d_scanner(d_val__)
{})
|