[comp.unix.programmer] yacc/bison question

chris@bwilab3.UUCP (Chris Curtin) (10/05/90)

I am looking for a way to have multiple yacc/bison routines in a program. I
also need to be able to name them anything, not just yyparse1 etc.

I know that doing a global replace with the preprocessor will not work because
of the use of globals in calls to library routines.

If this is possible it will make my life much easier and produce better quality
code. (Now I have to hand parse all input and it gets tedious and error prone).

Thanks in advance.

Chris Curtin

 ...!gatech!galbp!bwilab3!chris 

meissner@osf.org (Michael Meissner) (10/07/90)

In article <122@bwilab3.UUCP> chris@bwilab3.UUCP (Chris Curtin)
writes:

| I am looking for a way to have multiple yacc/bison routines in a program. I
| also need to be able to name them anything, not just yyparse1 etc.
| 
| I know that doing a global replace with the preprocessor will not work because
| of the use of globals in calls to library routines.
| 
| If this is possible it will make my life much easier and produce better quality
| code. (Now I have to hand parse all input and it gets tedious and error prone).

This seems to come up regularly on comp.compilers and comp.lang.misc,
which might have been better groups to ask.

In any case, bison has extensions to handle this with no problem --
RTFM.  The traditional ways to do it with yacc are to go through and
change the names with either sed or the preprocessor.  With sed, you
just change all 'yy' and 'YY' to some other prefix.  With the
preprocessor, you use #defines, and you can get burned if your vendor
changes the yacc skeleton file and some new name is added.

The relavant sections from the bison manual are quoated below (to get
a different named file, just use the -o <file> option, and -d and -v
will adjust themselves accordingly):

File: bison.info  Node: Multiple Parsers, Prev: Declarations, Up: Grammar File

Multiple Parsers in the Same Program
====================================

Most programs that use Bison parse only one language and therefore contain
only one Bison parser.  But what if you want to parse more than one
language with the same program?  Here is what you must do:

   * Make each parser a pure parser (*Note Pure Decl::).  This gets rid of
     global variables such as `yylval' which would otherwise conflict
     between the various parsers, but it requires an alternate calling
     convention for `yylex' (*Note Pure Calling::).

   * In each grammar file, define `yyparse' as a macro, expanding
     into the name you want for that parser.  Put this definition in
     the C declarations section (*Note C Declarations::).  For example:

          %{
          #define yyparse parse_algol
          %}

     Then use the expanded name `parse_algol' in other source files to
     call this parser.

   * If you want different lexical analyzers for each grammar, you can
     define `yylex' as a macro, just like `yyparse'.  Use
     the expanded name when you define `yylex' in another source
     file.

     If you define `yylex' in the grammar file itself, simply
     make it static, like this:

          %{
          static int yylex ();
          %}
          %%
          ... GRAMMAR RULES ...
          %%
          static int
          yylex (yylvalp, yyllocp)
               YYSTYPE *yylvalp;
               YYLTYPE *yyllocp;
          { ... }

   * If you want a different `yyerror' function for each grammar,
     you can use the same methods that work for `yylex'.

File: bison.info  Node: Pure Decl, Prev: Start Decl, Up: Declarations, Next: Decl Summary

Requesting a Pure (Reentrant) Parser
------------------------------------

A "reentrant" program is one which does not alter in the course of
execution; in other words, it consists entirely of "pure" (read-only)
code.  Reentrancy is important whenever asynchronous execution is possible;
for example, a nonreentrant program may not be safe to call from a signal
handler.  In systems with multiple threads of control, a nonreentrant
program must be called only within interlocks.

The Bison parser is not normally a reentrant program, because it uses
statically allocated variables for communication with `yylex'.  These
variables include `yylval' and `yylloc'.

The Bison declaration `%pure_parser' says that you want the parser
to be reentrant.  It looks like this:

     %pure_parser

The effect is that the the two communication variables become local
variables in `yyparse', and a different calling convention is used for
the lexical analyzer function `yylex'.  *Note Pure Calling::, for the
details of this.  The variable `yynerrs' also becomes local in
`yyparse' (*Note Error Reporting::).  The convention for calling
`yyparse' itself is unchanged.

File: bison.info  Node: Pure Calling, Prev: Token Positions, Up: Lexical

Calling Convention for Pure Parsers
-----------------------------------

When you use the Bison declaration `%pure_parser' to request a pure,
reentrant parser, the global communication variables `yylval' and
`yylloc' cannot be used.  (*Note Pure Decl::.)  In such parsers the
two global variables are replaced by pointers passed as arguments to
`yylex'.  You must declare them as shown here, and pass the
information back by storing it through those pointers.

     yylex (lvalp, llocp)
          YYSTYPE *lvalp;
          YYLTYPE *llocp;
     {
       ...
       *lvalp = value;  /* Put value onto Bison stack.  */
       return INT;      /* Return the type of the token.  */
       ...
     }


--
Michael Meissner	email: meissner@osf.org		phone: 617-621-8861
Open Software Foundation, 11 Cambridge Center, Cambridge, MA, 02142

Do apple growers tell their kids money doesn't grow on bushes?

salomon@ccu.umanitoba.ca (Dan Salomon) (10/13/90)

In article <122@bwilab3.UUCP> chris@bwilab3.UUCP (Chris Curtin) writes:
>
>
>I am looking for a way to have multiple yacc/bison routines in a program. I
>also need to be able to name them anything, not just yyparse1 etc.
>

I once needed two lex-yacc parsers in the same program.  I used the
stream editor "sed" to edit the C code generated by lex & yacc on one
of the parsers.  It replaced every occurence of "yy" with "ww".  This
worked because all lex-yacc externals start with "yy".  I also supplied
the needed external procedures such as "wwerror".  My sed script also
renamed the main parser routine, but kept the same number of letters,
just to be safe.

This approach worked fine, but it was just quick & dirty code for an
experiment; it wasn't production quality code.
-- 

Dan Salomon -- salomon@ccu.UManitoba.CA