DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦1b53f03b0⟧ TextFile

    Length: 13377 (0x3441)
    Types: TextFile
    Notes: UNIX file
    Names: »y1.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦f4b8d8c84⟧ UNIX Filesystem
        └─ ⟦this⟧ »cmd/yacc/y1.c« 

TextFile

/*
 * 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;
	}
}