[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
3.7.11 A Push Parser
(The current push parsing interface is experimental and may evolve. More user feedback will help to stabilize it.)
A pull parser is called once and it takes control until all its input is completely parsed. A push parser, on the other hand, is called each time a new token is made available.
A push parser is typically useful when the parser is part of a main event loop in the client's application. This is typically a requirement of a GUI, when the main event loop needs to be triggered within a certain time period.
Normally, Bison generates a pull parser. The following Bison declaration says that you want the parser to be a push parser (see section %define api.push_pull):
%define api.push_pull "push" |
In almost all cases, you want to ensure that your push parser is also a pure parser (see section A Pure (Reentrant) Parser). The only time you should create an impure push parser is to have backwards compatibility with the impure Yacc pull mode interface. Unless you know what you are doing, your declarations should look like this:
%define api.pure %define api.push_pull "push" |
There is a major notable functional difference between the pure push parser and the impure push parser. It is acceptable for a pure push parser to have many parser instances, of the same type of parser, in memory at the same time. An impure push parser should only use one parser at a time.
When a push parser is selected, Bison will generate some new symbols in
the generated parser. yypstate
is a structure that the generated
parser uses to store the parser's state. yypstate_new
is the
function that will create a new parser instance. yypstate_delete
will free the resources associated with the corresponding parser instance.
Finally, yypush_parse
is the function that should be called whenever a
token is available to provide the parser. A trivial example
of using a pure push parser would look like this:
int status; yypstate *ps = yypstate_new (); do { status = yypush_parse (ps, yylex (), NULL); } while (status == YYPUSH_MORE); yypstate_delete (ps); |
If the user decided to use an impure push parser, a few things about
the generated parser will change. The yychar
variable becomes
a global variable instead of a variable in the yypush_parse
function.
For this reason, the signature of the yypush_parse
function is
changed to remove the token as a parameter. A nonreentrant push parser
example would thus look like this:
extern int yychar; int status; yypstate *ps = yypstate_new (); do { yychar = yylex (); status = yypush_parse (ps); } while (status == YYPUSH_MORE); yypstate_delete (ps); |
That's it. Notice the next token is put into the global variable yychar
for use by the next invocation of the yypush_parse
function.
Bison also supports both the push parser interface along with the pull parser
interface in the same generated parser. In order to get this functionality,
you should replace the %define api.push_pull "push"
declaration with the
%define api.push_pull "both"
declaration. Doing this will create all of
the symbols mentioned earlier along with the two extra symbols, yyparse
and yypull_parse
. yyparse
can be used exactly as it normally
would be used. However, the user should note that it is implemented in the
generated parser by calling yypull_parse
.
This makes the yyparse
function that is generated with the
%define api.push_pull "both"
declaration slower than the normal
yyparse
function. If the user
calls the yypull_parse
function it will parse the rest of the input
stream. It is possible to yypush_parse
tokens to select a subgrammar
and then yypull_parse
the rest of the input stream. If you would like
to switch back and forth between between parsing styles, you would have to
write your own yypull_parse
function that knows when to quit looking
for input. An example of using the yypull_parse
function would look
like this:
yypstate *ps = yypstate_new (); yypull_parse (ps); /* Will call the lexer */ yypstate_delete (ps); |
Adding the %define api.pure
declaration does exactly the same thing to
the generated parser with %define api.push_pull "both"
as it did for
%define api.push_pull "push"
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |