[comp.unix.wizards] Linking two yacc

jxf@phobos.cis.ksu.edu (Jerry Frain) (02/22/90)

I recently wrote a program which requires two parsers.  Depending upon
the type of input received, the program will parse according to one of
two grammars.

I created a yacc file for each parser, tested them separately, and prepared
to link the objects into a larger program.  Unfortunately, that's as far as
I got.  Since yacc creates a lot of global variables when it makes the
y.tab.c files, there were many conflict errors when I tried to link the two
files.

I seem to recall a thread in this newsgroup about this problem quite some
time ago, but I did not pay any attention to the solution at the time.  

Anybody got any ideas as to how I can solve this dilemma?

Thanks in advance.  I'd be glad to post a summary, if there is much
interest.

--
Jerry Frain -- Professional Student           Kansas State University
Internet: jxf@phobos.cis.ksu.edu      Dept of Computing & Information Sciences
BITNET: MUSTANG@KSUVM.BITNET                      Manhattan, Kansas
UUCP: ...!{rutgers|textbell}!ksuvax1!phobos.cis.ksu.edu!jxf

alan@cogswell.Jpl.Nasa.Gov (Alan S. Mazer) (02/23/90)

In article <25E34681.3787@deimos.cis.ksu.edu>, jxf@phobos.cis.ksu.edu (Jerry Frain) writes:
| I created a yacc file for each parser, tested them separately, and prepared
| to link the objects into a larger program.  Unfortunately, that's as far as
| I got.  Since yacc creates a lot of global variables when it makes the
| y.tab.c files, there were many conflict errors when I tried to link the two
| files.

We have a program which uses two different grammars and the Makefile
runs one y.tab.c through sed to change the names of things.  I think
there's 40-some things to change.  Haven't had any problems with this.
If you or anyone else want it, you're welcome.

-- Alan				# "But seriously, what could go wrong?"
   ..!cit-vax!elroy!alan
   alan@elroy.jpl.nasa.gov

kon@mycroft.Stanford.EDU (Ronnie Kon) (02/23/90)

In article <25E34681.3787@deimos.cis.ksu.edu> jxf@phobos.cis.ksu.edu (Jerry Frain) writes:
>        Since yacc creates a lot of global variables when it makes the
>y.tab.c files, there were many conflict errors when I tried to link the two
>files.

	Not only does it make a lot of global variables, but the two
routines are both named yyparse, and both call yylex for scanning input.
There are two approaches to dealing with this, one correct and tedious to
implement, one a kludge that works every bit as well and is much, much, easier.

	The correct way to do this is to run the yacc output through a sed
script which replaces all the globals with unique names.  This will be a
pain to implement.

	The kludge is to simply sed with the command

		sed 's/\<yy/parser1_yy/g' < y.tab.c > parser1.c

for the first parser.  (The sed script for the second parser is left as an
exercize for the reader :-)).

	You then call these as parser1_yyparse() and parser2_yyparse(), and
you set up the scanners to be parser1_yylex() and parser2_yylex().  (If you
are using lex, you simply use the same sed scripts as for the yacc files,
and it all just works).  Note that the yytext and yylval variables (which you
are probably using) need not be changed.  The sed's will catch all instances
of them.
-- 
-------------------------------------------------------------------------------
Ronnie Kon				|     "I don't know about your brain,
ronnie@mindcraft.com			|     but mine is really bossy"
...!{decwrl,hpda}!mindcrf!ronnie	|		-- Laurie Anderson
-------------------------------------------------------------------------------

chris@mimsy.umd.edu (Chris Torek) (02/23/90)

(I have deleted an unnecessary `usa' Distribution: line.)

In article <39@mycroft.stanford.edu> kon@mycroft.Stanford.EDU (Ronnie Kon)
writes:
>The correct way to do this is to run the yacc output through a sed
>script which replaces all the globals with unique names. ...

Actually, since yacc is table driven, this is really not the `best' way
to do it either, since you wind up with duplicated code.

The `best' way depends on space/time tradeoffs.  If you want the least
space possible, merge the two grammars (and, if necessary, scanners)
and see if that gives smaller tables.  Depending on the degree of
commonality, it might or might not.  If you want speed over space, or
if the merged tables are larger, change the yacc parser to take
parameters giving the tables and (if necessary) the lexing function.
You can then share the parser skeleton (/usr/lib/yaccpar, or whatever
it is called on your system) while using separate tables.

In other words, instead of calling `yyparse()', you would call
`parse(&parsedata, &lexdata)', where `parsedata' is a structure
containing (pointers to) the parser tables and a function that
implements the actions, and where lexdata is a structure containing
(pointers to) the scanner tables and the lex function itself and a
function that implements the lexer actions.  (If the lexer for both
grammars are identical, you need not bother with `lexdata'.)

This would require substantial changes to yacc (and, if you use it
similarly, lex).  Changing the names is much easier.

Note that this technique does not work with code-driven scanners such
as those produced by GLA.  If, however, you were to mix GLA and yacc,
you could still do this for the parser (and instead of &lexdata, pass
a pointer to the GLA lexing function).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

hadley@ics.uci.edu (Tedd Hadley) (02/24/90)

jxf@phobos.cis.ksu.edu (Jerry Frain) writes:

>I seem to recall a thread in this newsgroup about this problem quite some
>time ago, but I did not pay any attention to the solution at the time.

>Anybody got any ideas as to how I can solve this dilemma?

   Here's a very practical (as opposed to pedantically correct) solution.

   Include the following ".h" file in your yacc file.
   Replace all <unique_name_here> with whatever name you wish.
   Call to parser becomes <unique_name_here>_yyparse()

--- yacc_unique.h ---

#define yyact		<unique_name_here>_yyact
#define yyback		<unique_name_here>_yyback
#define yybgin		<unique_name_here>_yybgin
#define yychar		<unique_name_here>_yychar
#define yychk		<unique_name_here>_yychk
#define yycrank		<unique_name_here>_yycrank
#define yydef		<unique_name_here>_yydef
#define yyerrflag	<unique_name_here>_yyerrflag
#define yyestate	<unique_name_here>_yyestate
#define yyexca		<unique_name_here>_yyexca
#define yyextra		<unique_name_here>_yyextra
#define yyfnd		<unique_name_here>_yyfnd
#define yyin		<unique_name_here>_yyin
#define yyinput		<unique_name_here>_yyinput
#define yyleng		<unique_name_here>_yyleng
#define yylex		<unique_name_here>_yylex
#define yylineno	<unique_name_here>_yylineno
#define yylook		<unique_name_here>_yylook
#define yylsp		<unique_name_here>_yylsp
#define yylstate	<unique_name_here>_yylstate
#define yylval		<unique_name_here>_yylval
#define yymatch		<unique_name_here>_yymatch
#define yymorfg		<unique_name_here>_yymorfg
#define yynerrs		<unique_name_here>_yynerrs
#define yyolsp		<unique_name_here>_yyolsp
#define yyout		<unique_name_here>_yyout
#define yyoutput	<unique_name_here>_yyoutput
#define yypact		<unique_name_here>_yypact
#define yyparse		<unique_name_here>_yyparse
#define yypgo		<unique_name_here>_yypgo
#define yyprevious	<unique_name_here>_yyprevious
#define yyr1		<unique_name_here>_yyr1
#define yyr2		<unique_name_here>_yyr2
#define yysbuf		<unique_name_here>_yysbuf
#define yysptr		<unique_name_here>_yysptr
#define yysvec		<unique_name_here>_yysvec
#define yytchar		<unique_name_here>_yytchar
#define yytext		<unique_name_here>_yytext
#define yytop		<unique_name_here>_yytop
#define yyunput		<unique_name_here>_yyunput
#define yyv		<unique_name_here>_yyv
#define yyval		<unique_name_here>_yyval
#define yyvstop		<unique_name_here>_yyvstop

--- yacc_unique.h ---

And best of all, no `sed' scripts.

++
   Tedd Hadley (hadley@ics.uci.edu)

gnb@bby.oz.au (Gregory N. Bond) (02/26/90)

Here is a script I use for making yacc output files static, so you can
link n of them in one binary.  I use it on the output of getdate.y to
make a general gate-parsing library.  Tried only on SunOs 3.5 and 4.0.3.
(It assumes the .y file contains a global routine that calls the
yyparse routine).

Usage: sed -f yaccstaticize.sed < y.tab.c > file.c

Greg.
-- 
Gregory Bond, Burdett Buckeridge & Young Ltd, Melbourne, Australia
Internet: gnb@melba.bby.oz.au    non-MX: gnb%melba.bby.oz@uunet.uu.net
Uucp: {uunet,pyramid,ubc-cs,ukc,mcvax,prlb2,nttlab...}!munnari!melba.bby.oz!gnb

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  yaccstaticize.sed
# Wrapped by gnb@baby on Mon Feb 26 10:29:39 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'yaccstaticize.sed' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'yaccstaticize.sed'\"
else
echo shar: Extracting \"'yaccstaticize.sed'\" \(93 characters\)
sed "s/^X//" >'yaccstaticize.sed' <<'END_OF_FILE'
Xs/^short yy/static &/
Xs/^int[ 	]*yy/static &/
Xs/^YY[LS]TYPE/static &/
Xs/^yyparse()/static &/
END_OF_FILE
if test 93 -ne `wc -c <'yaccstaticize.sed'`; then
    echo shar: \"'yaccstaticize.sed'\" unpacked with wrong size!
fi
# end of 'yaccstaticize.sed'
fi
echo shar: End of shell archive.
exit 0
--
Gregory Bond, Burdett Buckeridge & Young Ltd, Melbourne, Australia
Internet: gnb@melba.bby.oz.au    non-MX: gnb%melba.bby.oz@uunet.uu.net
Uucp: {uunet,pyramid,ubc-cs,ukc,mcvax,prlb2,nttlab...}!munnari!melba.bby.oz!gnb
-- 
Gregory Bond, Burdett Buckeridge & Young Ltd, Melbourne, Australia
Internet: gnb@melba.bby.oz.au    non-MX: gnb%melba.bby.oz@uunet.uu.net
Uucp: {uunet,pyramid,ubc-cs,ukc,mcvax,prlb2,nttlab...}!munnari!melba.bby.oz!gnb

johnson@ncrons.StPaul.NCR.COM (Wayne D. Johnson) (02/28/90)

In article <39@mycroft.stanford.edu> kon@mycroft.Stanford.EDU (Ronnie Kon) writes:
#In article <25E34681.3787@deimos.cis.ksu.edu> jxf@phobos.cis.ksu.edu (Jerry Frain) writes:
#>        Since yacc creates a lot of global variables when it makes the
#>y.tab.c files, there were many conflict errors when I tried to link the two
#>files.
#
#	The kludge is to simply sed with the command
#
#		sed 's/\<yy/parser1_yy/g' < y.tab.c > parser1.c

I have seen an implementation where they #defined the yy as
somthing else before the compile.  Who needs sed.



-- 
Wayne Johnson         |  Is a baby's life worth more than the right to
NCR Comten, Inc.      |  make a choice?  Babies are people too.
Roseville MN 55113    +-----------------------------------------------------
(Voice) 612-638-7665   (E-MAIL) W.Johnson@StPaul.NCR.COM

kon@wolverine.Stanford.EDU (Ronnie Kon) (03/01/90)

In article <238@ncrons.StPaul.NCR.COM> johnson@ncrons.StPaul.NCR.COM (Wayne D. Johnson) writes:
>#
>#	The kludge is to simply sed with the command
>#
>#		sed 's/\<yy/parser1_yy/g' < y.tab.c > parser1.c
>
>I have seen an implementation where they #defined the yy as
>somthing else before the compile.  Who needs sed?
>

	This will not work with a functioning C preprocessor.  Only complete
identifiers should be replaced.  Thus a variable named "yy" would get
changed, but "yytext" will not.
-- 
-------------------------------------------------------------------------------
Ronnie Kon				|     "I don't know about your brain,
ronnie@mindcraft.com			|     but mine is really bossy"
...!{decwrl,hpda}!mindcrf!ronnie	|		-- Laurie Anderson
-------------------------------------------------------------------------------

meo@stiatl.UUCP (Miles O'Neal) (03/18/90)

I just rename y.lex.c to something more useful, such as parse_newt.c.

Makefiles do this just fine, but even without make it's no trouble.

-Miles O'Neal
meo@SalesTech.com
emory!stiatl!meo