|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 13377 (0x3441)
Types: TextFile
Notes: UNIX file
Names: »y1.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/yacc/y1.c«
/*
* LALR-1 parser generator
*
* the comments previously here have been suppressed since they were
* boring
*/
#include "yacc.h"
main(argc,argv)
char *argv[];
{
options(argc,argv);
getfiles();
readrules();
ntprod();
ntderive();
listgram();
if( nerrors )
cleanup(1);
ntempty();
if( nerrors )
cleanup(1);
genstates();
genslist();
sttrans();
genlook();
go2out();
paout();
callopt();
cleanup(0);
}
getfiles()
{
if( gramy==NULL )
usage();
if( strcmp(gramy,"-")==0 )
defin = stdin;
else
if( (defin = fopen(gramy,"r")) == NULL )
yyerror(!FATAL, "cannot open grammar file %s", gramy);
mktemp(acttmp);
mktemp(opttmp);
if( (actout = fopen(acttmp,"w")) == NULL )
yyerror(!FATAL, "cannot create action temp file %s", acttmp);
if( (tabout = fopen(ytabc,"w")) == NULL )
yyerror(!FATAL, "cannot create output file %s", ytabc);
if( (fhdr = fopen(ytabh, "w")) == NULL )
yyerror(!FATAL, "cannot create %s", ytabh);
if( verbose )
if( (listout = fopen(youtput,"w")) == NULL )
yyerror(NLNO, "cannot open listing file %s", youtput);
if ((optout = fopen(opttmp, "w")) == NULL
|| (optout = freopen(opttmp, "r+w", optout)) == NULL)
yyerror(NLNO, "open error temp %s", opttmp);
if( nerrors )
cleanup(2);
}
rewopt()
{
fseek(optout, 0L, 0);
}
/*
* for each non-terminal, generate a list of productions which the
* the non terminal derives
*/
ntprod()
{
register i;
register struct sym *sp;
/* first run down the production table, counting references to
all the non terminals. */
for(i=0; i<nnonterm; i++)
ntrmptr[i]->s_nprods = 0;
for(i=0; i<nprod; i++)
ntrmptr[-prdptr[i]->p_left-NTBASE]->s_nprods++;
for(i=0; i<nnonterm; i++)
if( ntrmptr[i]->s_nprods==0 )
yyerror(NLNO|!FATAL, "non terminal %s not defined",
ntrmptr[i]->s_name);
if( nerrors )
cleanup(1);
/* now allocate list pointers for each non-terminal */
for(i=0; i<nnonterm; i++) {
sp = ntrmptr[i];
sp->s_prods = (struct prod **)yalloc(sp->s_nprods, sizeof *sp->s_prods);
sp->s_nprods = 0; /* il sera recharge a la suite */
}
/* finally, run down the production table again filling in the
list pointers for the corresponding non terminal */
for(i=0; i<nprod; i++) {
sp = ntrmptr[ -prdptr[i]->p_left-NTBASE ];
sp->s_prods[sp->s_nprods++] = prdptr[i];
}
}
/*
* assure that all non-terminals generate a token string
* algorithm:
* assume a priori that no non-terminal generates a token string
* if a non terminal contains a production which consists only
* of non-terminals generating a token string, and terminals
* then it generates a token string
* cycle on this until no new non terminals are found
* - a similar procedure applies for finding out which non terminals
* generate the empty string
*/
ntderive()
{
register i, j;
register struct sym *sp;
register struct prod *pp;
int *ip;
int changed;
for(i=0; i<nnonterm; i++)
ntrmptr[i]->s_flags &= ~DERIV;
do {
changed = 0;
for(i=0; i<nnonterm; i++) {
sp = ntrmptr[i];
if( sp->s_flags&DERIV )
continue;
for(j=0; j<sp->s_nprods; j++) {
pp = sp->s_prods[j];
for(ip=pp->p_right; *ip!=-1; ip++)
if( *ip>=NTBASE &&
(ntrmptr[*ip-NTBASE]->s_flags&DERIV)==0 )
break;
if( *ip == -1 ) {
sp->s_flags |= DERIV;
changed++;
break;
}
}
}
} while( changed );
for(i=0; i<nnonterm; i++)
if( (ntrmptr[i]->s_flags&DERIV)==0 )
yyerror(NLNO|!FATAL, "nonterminal %s derives no token string",
ntrmptr[i]->s_name);
if( nerrors )
cleanup(1);
}
/*
* find out which non-terminals derive the empty string
* algorithm is simple
* if the non-terminal has a production deriving the empty string
* it derives the empty string trivially
* otherwise if it consists only of productions which can derive the
* empty string, then it derives the empty string as well
*/
ntempty()
{
register *kp;
register struct prod **ppp;
register struct sym *sp;
int i, changed;
for(i=0; i<nnonterm; i++)
ntrmptr[i]->s_flags &= ~DERIV;
do {
changed = 0;
for(i=0; i<nnonterm; i++) {
sp = ntrmptr[i];
if( sp->s_flags&DERIV )
continue;
for(ppp=sp->s_prods; ppp<&sp->s_prods[sp->s_nprods]; ppp++) {
for(kp = (*ppp)->p_right; *kp!=-1; kp++ )
if( *kp<NTBASE ||
(ntrmptr[*kp-NTBASE]->s_flags&DERIV)==0 )
break;
if( *kp==-1 ) {
sp->s_flags |= DERIV;
changed++;
break;
}
}
}
} while( changed );
}
/* some useful local variables */
static newgen; /* communication between genstates and install */
static char *ntp; /* buffer for use by chklhs */
genstates()
{
extern struct sitem *nititem;
register k, sno;
int i;
struct tgo tgo;
struct ntgo ntgo;
/* initialize the list of states associated with each nt to empty */
if( verbose )
fprintf(listout, "\nAutomaton state description:\n\n");
for(i=0; i<nnonterm; i++)
ntrmptr[i]->s_nstates = 0;
ntp = yalloc(nnonterm, sizeof *ntp); /* array used by "install" */
nititem->i_nitems = 1;
nititem->i_items[0] = prdptr[0]->p_right;
closure();
install();
i = 0;
do {
newgen = 0; /* newgen is flagged by the install routine */
for(; i<nstates; i++) {
fwrite(&i, sizeof i, 1, optout); /* sync number */
states[i].s_tgo = 0;
for(k=0; k<nterm; k++)
if( (sno = go2(items[i], k)) >= 0 ) {
states[i].s_tgo++;
tgo.tg_st = sno;
tgo.tg_trm = k;
fwrite(&tgo, sizeof tgo, 1, optout);
}
states[i].s_ntgo = 0;
for(k=0; k<nnonterm; k++)
if( (sno = go2(items[i], k+NTBASE)) >= 0 ) {
states[i].s_ntgo++;
ntgo.ng_st = sno;
ntgo.ng_nt = k+NTBASE;
ntgo.ng_rel = NULL; /* MWC DSC */
fwrite(&ntgo, sizeof ntgo, 1, optout);
}
states[i].s_nred = 0;
for(k=0; k<items[i]->i_nitems; k++)
if( *(items[i]->i_items[k]) == -1 )
states[i].s_nred++;
states[i].s_tgos = states[i].s_ntgos =
states[i].s_reds = NULL; /* MWC DSC */
}
} while( newgen );
free(ntp);
}
/*
* generate the closure of a state (found in global variable `nititem'
* Algorithm:
* - look at every non terminal's after every '.' item pointer
* - add all the productions associated with this non-terminal
* to the state (the '.' being at the beginning of the rhs) unless
* they are already there. It suffices to test if one of them is
* already there, since productions are added to the closure according
* according to their lhs
* repeat this procedure until no new items are added.
*
* "It can be shown that (this procedure) computes exactly the sets
* of items that are valid for gamma X [Aho and Ullmann 1972]"
*/
closure()
{
register j, **ipp;
register struct prod **ppp;
struct sitem *itp;
struct sym *sp;
int i, changed, nt;
itp = nititem;
for(i=0; i<nnonterm; i++)
ntrmptr[i]->s_flags &= ~CPRES;
for(i=0; i<itp->i_nitems; i++)
/* kludge: requires p.left & p.rights contigou▶08◀▶08◀uous */
if( (nt = *(itp->i_items[i]-1)) < 0 ) /* ARE THEY???? */
ntrmptr[-nt-NTBASE]->s_flags |= CPRES;
do {
changed = 0;
for(i=0; i<itp->i_nitems; i++) {
nt = *(itp->i_items[i]);
if( nt>=NTBASE && ((sp = ntrmptr[nt-NTBASE])->s_flags
&CPRES)==0 ) {
sp->s_flags |= CPRES;
changed = 1;
ppp = sp->s_prods;
ipp = &itp->i_items[itp->i_nitems];
itp->i_nitems += j = sp->s_nprods;
bounded(itp->i_nitems, MAXITEM, "items in state");
do
*ipp++ = (*ppp++)->p_right;
while( --j );
}
}
} while( changed );
}
/*
* add the state in `nititem' to the collection of sets of accessible
* items, returning the state pointer
* the real work is concerned with finding out whether the set is there
* already or not
* we sort the items in nititem, compare with every set in "items",
* and return the old state pointer if its there already
*/
install()
{
register n, **ipp1, **ipp2;
struct sitem *itp, *itp1;
int i;
itp = nititem;
bubble(itp->i_items, itp->i_nitems);
for(i=0; i<nstates; i++) {
itp1 = items[i];
if( (n = itp->i_nitems) != itp1->i_nitems )
continue;
ipp1 = itp->i_items;
ipp2 = itp1->i_items;
do
if( *ipp1++ != *ipp2++ )
break;
while( --n );
if( n==0 )
break;
}
if( i==nstates ) {
bounded(nstates,maxstates,"states");
chklhs();
itp1 = (struct sitem *)yalloc(1, sizeof *itp1 + itp->i_nitems *
sizeof itp->i_items[0]);
copyb(itp, itp1, sizeof *itp1 + itp->i_nitems *
sizeof itp->i_items[0]);
newgen = 1;
items[nstates] = itp1;
if( verbose )
prstate(nstates, listout);
nstates++;
}
return( i );
}
go2(itp, tk)
struct sitem *itp;
int tk;
{
register **ipp1, **ipp, n;
nititem->i_nitems = 0;
ipp1 = nititem->i_items;
ipp = itp->i_items;
n = itp->i_nitems;
do {
if( **ipp == tk ) {
nititem->i_nitems++;
*ipp1++ = *ipp+1;
}
ipp++;
} while( --n );
if( nititem->i_nitems==0 )
return( -1 );
else {
closure();
return( install() );
}
}
chklhs()
{
register n, **ipp;
register char *cp;
int nt;
n = nnonterm;
cp = ntp;
do *cp++ = 0; while( --n );
ipp = nititem->i_items;
n = nititem->i_nitems;
cp = ntp;
do
if( (nt = (*ipp++) [-1]) < 0 )
cp[ -nt-NTBASE ] = 1;
while( --n );
for(n=0; n<nnonterm; n++)
if( cp[n] )
ntrmptr[n]->s_nstates++;
}
/*
* for each nonterminal generate a list of items
* containing items with all of the rhs of a production
* whose lhs is the non-terminal after the '.'
*/
genslist()
{
register struct sym *sp;
register i, j;
int *ip;
int *stp;
for(i=j=0; i<nnonterm; i++)
j += ntrmptr[i]->s_nstates;
stp = (int *)yalloc(j, sizeof *stp);
for(i=0; i<nnonterm; i++) {
sp = ntrmptr[i];
sp->s_states = stp;
stp += sp->s_nstates;
sp->s_nstates = 0; /* a recharcher dans le boucle suivant */
}
for(i=0; i<nnonterm; i++) {
sp = ntrmptr[i];
ip = sp->s_prods[0]->p_right; /* pick an item, any item */
for(j=0; j<nstates; j++)
if( pitem(ip, items[j]) )
sp->s_states[sp->s_nstates++] = j;
}
}
/* binary search for an item in a state */
pitem(ip,itp)
int *ip;
register struct sitem *itp;
{
register int *el, nb;
int ub, lb;
lb = 0;
ub = itp->i_nitems-1;
do {
nb = (ub+lb) / 2;
if( (el = itp->i_items[nb]) < ip )
lb = nb+1;
else if( el > ip )
ub = nb-1;
else
return(1);
} while( lb<=ub );
return(0);
}
/*
* linear insertion sort really.
* the decision not to use bubbbbbbbbbbbble sort is thanks to Randall
* and to his cs240b notes
* (p.s. -- i hate sorting)
*/
bubble(ipp,n)
register **ipp;
int n;
{
register **min, **jpp;
int m, *t; /* MWC DSC */
do {
m = n;
min = jpp = ipp;
do {
if( *jpp < *min )
min = jpp;
jpp++;
} while( --m );
t = *min;
*min = *ipp;
*ipp++ = t;
} while( --n );
}
copyb(sp,dp,n)
register char *sp, *dp;
register n;
{
do
*dp++ = *sp++;
while( --n );
}
cleanup(err)
{
unlink(acttmp);
unlink(opttmp);
stats();
exit(err);
}
stats()
{
extern nsrconf, nrrconf;
if( !pstat && (nsrconf || nrrconf) ) {
if( nrrconf ) {
fprintf(stderr, "%d R/R conflict", nrrconf);
if( nrrconf != 1 )
fprintf(stderr, "s");
}
if( nrrconf && nsrconf )
fprintf(stderr, " and ");
if( nsrconf ) {
fprintf(stderr, "%d S/R conflict", nsrconf);
if( nsrconf != 1)
fprintf(stderr, "s");
}
fprintf(stderr, "\n");
}
if( verbose )
stat1(listout);
if( pstat )
stat1(stdout);
}
stat1(f)
FILE *f;
{
extern nsrconf, nrrconf, yygodef, yypact, yyredns;
extern ndupgos, ndupacts;
extern yydefact;
fprintf(f, "Statistics:\n");
fprintf(f, "%d/%d tokens, %d/%d non terminals\n", nterm, maxterm,
nnonterm, maxnterm);
fprintf(f, "%d/%d productions, %d/%d states\n", nprod, maxprod,
nstates, maxstates);
fprintf(f, "%d goto entries; %d saved by goto default\n",
yyredns, yygodef);
fprintf(f, "%d parsing actions; %d saved by default\n",
yypact, yydefact);
fprintf(f, "%d duplicated goto entries saved; %d actions\n",
ndupgos, ndupacts);
if( nsrconf || nrrconf )
fprintf(f, "%d R/R conflicts, %d S/R conflicts\n",
nrrconf, nsrconf);
}
char *
yalloc(n, s)
{
register char *cp;
if( cp = calloc(n, s) )
return(cp);
yyerror(NLNO|FATAL, "storage overflow (requested %d)\n", n*s);
}
/*
* transform the state representation
*/
sttrans()
{
register j, k;
int i, totgo, tontgo;
register struct state *stp;
struct tgo *tgp;
struct ntgo *ngp;
/* a la pubelle !! */
for(i=0; i<nstates; i++)
free(items[i]);
free(items);
if( yydebug )
fprintf(listout,"Automaton transition graph:\n\n");
for(i=totgo=0; i<nstates; i++)
totgo += states[i].s_tgo;
for(i=tontgo=0; i<nstates; i++)
tontgo += states[i].s_ntgo;
tgp = (struct tgo *)yalloc(totgo, sizeof *tgp);
ngp = (struct ntgo *)yalloc(tontgo, sizeof *ngp);
rewopt();
for(j=0; j<nstates; j++) {
if( yydebug )
fprintf(listout, "State %d:\n\n", j);
stp = &states[j];
if( fread(&i, sizeof i, 1, optout)!=1 || i!=j )
yyerror(NLNO|FATAL, "temp file i/o error");
fread(tgp, sizeof *tgp, stp->s_tgo, optout);
stp->s_tgos = tgp;
stp->s_ntgos = ngp;
if( yydebug )
for(k=0; k<stp->s_tgo; k++)
fprintf(listout, "\t%s\t%d\n",
ptosym(stp->s_tgos[k].tg_trm),
stp->s_tgos[k].tg_st);
fread(ngp, sizeof *ngp, stp->s_ntgo, optout);
if( yydebug )
for(k=0; k<stp->s_ntgo; k++)
fprintf(listout, "\t%s\t%d\n",
ptosym(stp->s_ntgos[k].ng_nt),
stp->s_ntgos[k].ng_st);
tgp += stp->s_tgo;
ngp += stp->s_ntgo;
}
}