/*	@(#)ld.lex	2.1		*/
%{
static char ID[] = "@(#) ld.lex: 1.7 3/13/83";
#include "system.h"
#include <stdio.h>
#include <signal.h>
#include "bool.h"
#include "paths.h"
#include "sgs.h"
#include "structs.h"		/* global structure definitions  */
#include "extrns.h"		/* external function definitions */
#include "y.tab.h"		/* tokens generated by yacc      */

#if !ONEPROC || TRVEC
#include "tv.h"
#include "ldtv.h"
#endif

#include "aouthdr.h"
#if ONEPROC
#include "instr.h"
#endif

extern char version[];		/* ld version information */

/*
 *	There are four start states for the lex parse:
 *
 *	A	: look for initial keyword of a ld directive
 *	MEMoREG	: scan a ld directive
 *	COMA	: skip a stand-alone comment
 *	COMoMR	: skip a comment at the end of a directive
 */

#define RET1(a)   {yylval.ivalue=a;moveit(1,a);return(a);}
#define RET2(a,b) {yylval.sptr=a;moveit(2,yylval.sptr);return(b);}
#define RET3(a,b) {yylval.lptr=a;moveit(3,yylval.lptr);return(b);}



#define LSAVSIZE 6
static long lsavarea[LSAVSIZE];	/* local save area for integer tokens */
static int lsavndx = 0;
extern long *savelng();

#define CSAVSIZE 1024
static char csavarea[CSAVSIZE];	/* local save area for string tokens */
static char *csavptr = &csavarea[0];
extern char *savestr();

char inline[256];		/* global save area for the current input line */
char *inptr = &inline[0];

char **argptr;		/* main procedure argument list */
int argcnt;		/*	and count		*/


extern int in_y_exp;	/*	in_y_exp :
			 *		TRUE  : yacc is parsing assignment
			 *		FALSE : yacc is not in assignment
			 *
			 *	See explanation is ld.yac.
			 */

int	assigncnt;	/* number of assignment slots		*/


#if FLEXNAMES
#	define STRBASE 6144
#else
#	define STRBASE 3072
#endif
/*eject*/
%}
%start A MEMoREG COMA COMoMR
%%
%{
		long longint;	/* local variables used in processing */
		char *p;	/* numbers and strings		      */
%}

<A>"/*"		BEGIN COMA;
<MEMoREG>"/*"	BEGIN COMoMR;
<COMA>"*/"	BEGIN A;
<COMoMR>"*/"	BEGIN MEMoREG;
<COMA,COMoMR>.	;

<A>MEMORY	{ BEGIN MEMoREG; RET1(MEMORY); } 
<A>REGIONS	{ BEGIN MEMoREG; RET1(REGIONS); } 
<A>TV		{ BEGIN MEMoREG; RET1(TV); }

<A>SECTIONS	RET1(SECTIONS);
<A>DSECT	RET1(DSECT);
<A>NOLOAD	RET1(NOLOAD);
<A>COPY		RET1(COPY);

<MEMoREG>"}"		{ BEGIN A; RET1(RBRACE); }
<MEMoREG>ORIGIN|origin|org|o   RET1(ORG);
<MEMoREG>LENGTH|length|len|l   RET1(LEN);
<MEMoREG>SPARE|spare|s	RET1(SPARE);
<MEMoREG>RANGE|range	RET1(RANGE);
<MEMoREG>ASSIGN|assign	RET1(ASSIGN);

<A,MEMoREG>"."		RET1(DOT);
<A,MEMoREG>"}"		RET1(RBRACE);
<A,MEMoREG>"{"		RET1(LBRACE);
<A,MEMoREG>")"		RET1(RPAREN);
<A,MEMoREG>"("		RET1(LPAREN);
<A,MEMoREG>":"		RET1(COLON);
<A,MEMoREG>";"		RET1(SEMICOL);
<A,MEMoREG>"-"		RET1(MINUS);
<A,MEMoREG>"="		RET1(EQ);
<A,MEMoREG>">"		RET1(GT);
<A,MEMoREG>","		RET1(COMMA);
<A,MEMoREG>"&"		RET1(AND);
<A,MEMoREG>"&&"		RET1(ANDAND);
<A,MEMoREG>"|"		RET1(OR);
<A,MEMoREG>"||"		RET1(OROR);
<A,MEMoREG>"=="		RET1(EQEQ);
<A,MEMoREG>"!="		RET1(NE);
<A,MEMoREG>"~"		RET1(BNOT);
<A,MEMoREG>"!"		RET1(NOT);
<A,MEMoREG>"/"		RET1(DIV);
<A,MEMoREG>"*"		RET1(MULT);
<A,MEMoREG>"%"		RET1(PC);
<A,MEMoREG>"<"		RET1(LT);
<A,MEMoREG>">="		RET1(GE);
<A,MEMoREG>"<="		RET1(LE);
<A,MEMoREG>"<<"		RET1(LSHIFT);
<A,MEMoREG>">>"		RET1(RSHIFT);
<A,MEMoREG>"+"		RET1(PLUS);
<A,MEMoREG>"+="		RET1(PLUSEQ);
<A,MEMoREG>"-="		RET1(MINUSEQ);
<A,MEMoREG>"*="		RET1(MULTEQ);
<A,MEMoREG>"/="		RET1(DIVEQ);
<A,MEMoREG>ALIGN|align	RET1(ALIGN);
<A,MEMoREG>BLOCK|block	RET1(BLOCK);
<A,MEMoREG>GROUP|group	RET1(GROUP);
<A,MEMoREG>PHY|phy	RET1(PHY);


"\n"	{
	lineno++;
	inptr = &inline[0];
	}
[ \t]+	{
	*inptr++ = ' ';
	*inptr   = '\0';
	}


<A,MEMoREG>[0][0-7]*	{
		longint = 0L;
		for(p=yytext+1; *p != '\0'; p++)  {
			longint = longint * 8 + (*p-'0');
			}
		RET3(savelng(longint), LONGINT);
		}
<A,MEMoREG>[0-9]+	{
		longint = 0L;
		for(p=yytext; *p != '\0'; p++)  {
			longint = longint * 10 + (*p-'0');
			}
		RET3(savelng(longint), LONGINT);
		}
<A,MEMoREG>0[Xx][0-9a-fA-F]+  {
		longint = 0L;
		for(p=yytext+2; *p != '\0'; p++)  {
			longint = longint << 4;
			if (*p >= '0' && *p <= '9')
				longint += *p-'0';
			else if (*p >= 'a' && *p <= 'f')
				longint += *p-'a'+10;
			else longint += *p-'A'+10;
			}
		RET3(savelng(longint), LONGINT);
		}

<A,MEMoREG>[a-zA-Z0-9$._]+"/"("*"|"=")	{
			yyless(yyleng-2);
			RET2(savestr(yytext), NAME);
		}

<A,MEMoREG>[a-zA-Z0-9$._/]+"/"("*"|"=")	{
			if ( in_y_exp )
				REJECT;
			yyless(yyleng-2);
			RET2(savestr(yytext), FILENAME);
		}

<A,MEMoREG>[a-zA-Z0-9$._]+		{
			RET2(savestr(yytext), NAME);
		}

<A,MEMoREG>[a-zA-Z0-9$._/]+		{
			if ( in_y_exp )
				REJECT;
			RET2(savestr(yytext), FILENAME);
		}
%%
/*eject*/
main(argc,argv)
int argc;
char *argv[];
{

/*
 * This is the MAIN procdure for PASS 1 of ld
 *
 * PASS 1 is the parsing pass:
 *	1. The ld command line, and any specified ifiles, are
 *		scanned for good syntax.
 *	2. Control blocks are constructed, containing the information
 *		extracted from the input.
 *	3. If there are no errors, the control blocks are written out
 *		to a "transfer file", for reading by PASS 2.
 *	4. If there are no errors, PASS 2 is called via a system 
 *		"execl" call.
 */

/*
 * Initialize PASS 1
 */

	initpass1();
	argptr = argv;
	argcnt = argc;

/*
 * Process the command-line arguments to ld
 */

	lineno = 0;
	curfilnm = savefn("*command line*");

	while( --argcnt )
		if( **++argptr == '-' )
			/*
			 * The argument is a flag
			 */
			pflags( ++(*argptr), FALSE );
		else {
			/*
			 * The argument is a file name
			 */
			BEGIN A;
			filespec(*argptr);
			}
#if MC68 && UNIX
	/* 
	look for 'default.ld' file in the library dirs if no SECTION's seen 
	*/
	if (bldoutsc.head == NULL)
		{
		BEGIN A;
		default_ld();
		}
#endif

/*
 * Perform a consistency check among the ld flags:
 *	1. "-h" and "-X" flags
 *	2. "-ild", "-r", and "-a" flags
 *	3. "-r" and "-s" flags
 *	4. "-p" and "-B" flags
 *
 * Assign default values to the ld flags
 *	1. "-h" flag
 *	2. "-a" flag
 *	3. "-p" flag
 */

	if( Xflag )
		if( hflag > 0 ) {
			if( hflag < sizeof(AOUTHDR) )
				lderror(1, 0,NULL, "optional header size (%d bytes) is too small to contain the UNIX a.out header (%d bytes)",
					hflag, sizeof(AOUTHDR) );
			}
		else
			hflag = sizeof(AOUTHDR);
#if ILDOPT
	if (ildflag) {
		rflag = 1;
		if (sflag) {
			lderror (0, 0, NULL, "both -ild and -s flags are set. -s flag turned off");
			sflag = 0;
		}
	}
#endif
	if( rflag  &&  sflag ) {
		lderror(0, 0,NULL, "both -r and -s flags are set. -s flag turned off" );
		sflag = 0;
		}
	if ( Bflag && (pflag > 0) && (pflag < Bflag)) {
		lderror(0, 0, NULL, "pflag(%d) less than Bflag, set to value of Bflag(%d)\n",
			pflag, Bflag);
		pflag = Bflag;
		}
	if( ! rflag )
		aflag = 1;

/*
 * Supply version information
 */

	if( Vflag ) {
		fprintf( stderr, "\n%sld : %s : Version %s",
			SGSNAME, RELEASE, version );
		if( Vflag == 2 ) {
#if AR16WR
 			fprintf( stderr, " : PDP 11/70-45 : " );
#endif
#if AR32WR
			fprintf( stderr, " : VAX 11/780 : " );
#endif
#if ! AR16WR && ! AR32WR
#ifdef u3b
 			fprintf( stderr, " : 3B-20 : " );
#else
			fprintf( stderr, " : non-DEC : ");
#endif
#endif
#if TS
 			fprintf( stderr, "UN*X TS" );
#else
 			fprintf( stderr, "UN*X" );
#endif
			}
		fprintf( stderr, "\n" );
		}

/*
 * Exit if any errors were found, or if this is a "parse only"
 * run
 */

	if( (errlev != 0)  ||  (cflag == 1) ) {
#if !ONEPROC
		unlink( trnname );
#endif
		exit(errlev);
		}

/*
 * Call PASS 2
 */

#if ONEPROC
	pass2();
}
#else
	callpass2();

	unlink( trnname );
	lderror(2, 0,NULL, "failure to load pass 2 of %sld", SGS);
}
/*eject*/
ldexit()
{

/*
  * PASS 1: clean up and exit after a fatal error
 */

	signal(SIGINT, SIG_IGN);
	signal(SIGQUIT, SIG_DFL);
	signal(SIGTERM, SIG_IGN);
	signal(SIGHUP, SIG_DFL);

	exit(13);  /* unlucky break */
}
/*eject*/
#endif
long *
savelng(l)
long l;
{

/*
 * Copy a long token into local save area and return a pointer to it.
 *
 * The save area is used as a circular buffer
 */

	lsavndx++;
	lsavndx %= LSAVSIZE;
	lsavarea[lsavndx] = l;

	return( &lsavarea[lsavndx] );
}




char *
savestr(p) 
char *p;
{

/*
 * Copy a string into local save area and return a pointer to it
 *
 * The save area is used as a circular buffer
 */

	register char *saveptr;

	if( csavptr > (csavarea + CSAVSIZE - 256) )
		csavptr = csavarea;
	saveptr = csavptr;

	while( *csavptr++ = *p++ );

	return( saveptr );
}




moveit(type, value)
int type, value;
{
	register char *p;

	p = &yytext[0];

	while( *inptr++ = *p++ );
	inptr--;

#if DEBUG
	if( dflag > 3 ) {
		fprintf(stderr, "line: <%s> return: <", inline);
		switch( type ) {
		case 1:
			fprintf(stderr, "%d>\n", value);
			break;
		case 2:
			fprintf(stderr, "%s>\n", (char *) value);
			break;
		case 3:
			fprintf(stderr, "%08lx>\n", * (long *) value);
			break;
		}
		}
#endif
}
/*eject*/
initpass1()
{
	register int oldmode;
	int ldexit();
#if ONEPROC
	long times();
#endif

/*
 * Set the following signals to be caught, unless ld is running in the
 * background. In this case, leave them set at "ignore"
 */

	if( signal(SIGINT, ldexit)  ==  SIG_IGN )
		signal(SIGINT, SIG_IGN);
	if( signal(SIGHUP, ldexit)  ==  SIG_IGN )
		signal(SIGHUP, SIG_IGN);
	if( signal(SIGQUIT, ldexit)  ==  SIG_IGN )
		signal(SIGQUIT, SIG_IGN);


#if ONEPROC
	ttime = times(&ptimes);
#else
/*
 * Create the "transfer file" used to pass information to PASS 2
 */

	sprintf(trnname, "%s/%s", TMPDIR, "ldXXXXX");
	mktemp(trnname);

	oldmode = umask( 0 );
	if( close( creat(trnname,0644) ) == -1 ) {
		umask( oldmode );
		lderror(2, 0,NULL, "can't create intermediate %sld file %s",
			SGS, trnname);
		}
	umask( oldmode );
#endif

/*
 * Allocate the global file name save area
 */

	strbase = myalloc(STRBASE);
	strnext = strbase;
	strlimit = strbase + STRBASE;

#if ONEPROC && (!NOSDP)
	/*
	 * Initialize the Software Demand Paging System
	 */
	syminit();
#endif
}
/*eject*/
#if !ONEPROC
callpass2()
{

/*
 * Output PASS 1 information to the "transfer file"
 *
 *	1. reserve space for flags and list headers
 *	2. output lists
 *	3. output flags and list headers
 */

	trnfdes = fopen(trnname, "w");
	skp_tf_hdr();
	wrt_tf();
	wrt_tf_hdr();
	fclose( trnfdes );

/*
 * Exit, if this is a "generate transfer file run" only
 */

	if( cflag == 2 ) {
		fprintf( stderr, "ld transfer file name: %s\n", trnname );
		exit(0);
		}
#if DEBUG
	if( dflag > 2 )
		fprintf( stderr, "ld transfer file name: %s\n", trnname );
#endif

/*
 * Execute PASS 2
 */

	execl(LD2, LD2, trnname, 0);

}
/*eject*/
skp_tf_hdr()
{

/*
 * Reserve space for control and descriptor information collected during
 * PASS 1
 *
 * This information is of fixed length, and comes at the very beginning
 * of the transfer file
 */

	register long length;

	length = 
		7 * sizeof(int)		    +	/* list sizes	    */
		13 * sizeof(char)	    +	/* flags	    */
#if UNIX || XL
		1 * sizeof(char)	    +	/* xflag	    */
#endif
#if ILDOPT
		1 * sizeof(char)	    +	/* ildflag	    */
#endif
#if PAGING
		1 * sizeof(char)	    +	/* Fflag	    */
#endif
#if PAGING || UNIX
		1 * sizeof(char)	    +	/* zflag	    */
#endif
#if COMMON
		2 * sizeof(char)	    +	/* tflag and Mflag  */
#endif
		3 * sizeof(int)		    +	/* control values   */
		3 * sizeof(short)	    +	/* VStamp, fill and magic   */
		128			    +	/* output file name */
		8			    +	/* program entry pt */
		sizeof(TVINFO)		    +   /* tv information   */
		1 * sizeof(int);		/* flags + counts   */

	fseek( trnfdes, length, 0 );
}
/*eject*/
wrt_tf()
{

/*
 * Output the bulk of the information extracted from PASS 1:
 *
 *	1. The names of input ifiles, input *.o and archive files, and
 *		output sections
 *	2. The data structures describing the ld directives
 */

	MEMTYPE *outds1();
	REGION *outds2();
	ACTITEM *outds3(), *outds4(), *outds6();
	TVASSIGN *outds8();

/*
 * 1. Output saved strings
 */

	fwrite( strbase, 1, (strnext - strbase), trnfdes );


/*
 * 2a. Output DEFSYM data structures
 */

	symcnt = 0;
	if( symlist.head ) {
		register ACTITEM *a;
		a = (ACTITEM *) symlist.head;
		while( a ) {
			a = outds3(a);
			symcnt++;
			}
		}

/*
 * 2b. Output MEMTYPE data structures
 */

	memcnt = 0;
	if( memlist.head ) {
		register MEMTYPE *m;
		m = (MEMTYPE *) memlist.head;
		while( m ) {
			m = outds1(m);
			memcnt++;
			}
		}

/*
 * 2c. Output REGION data structures
 */

	regcnt = 0;
	if( reglist.head ) {
		register REGION *r;
		r = (REGION *) reglist.head;
		while( r ) {
			r = outds2(r);
			regcnt++;
			}
		}

/*
 * 2d. Output information on input *.o and archive library files
 */

	ldfcnt = 0;
	if( ldfilist.head ) {
		register ACTITEM *a;
		a = (ACTITEM *) ldfilist.head;
		while( a ) {
			a = outds3(a);
			ldfcnt++;
			}
		}
	

/*
 * 2e. Output information on output sections
 */

	bldcnt = 0;
	if( bldoutsc.head ) {
		register ACTITEM *a;
		a = (ACTITEM *) bldoutsc.head;
		while( a ) {
			a = outds4(a);
			bldcnt++;
			}
		}


/*
 * 2f. Output information on assignments
 */

	expcnt = 0;
	if( explist.head ) {
		register ACTITEM *a;
		a = (ACTITEM *) explist.head;
		while( a ) {
			a = outds6(a);
			expcnt++;
			}
		}

/*
 * 2g. Output information on slot assignments
 */

	tvslotcnt = 0;
	if (tvslot1 != NULL) {
		register TVASSIGN *s;
		s = tvslot1;
		while (s != NULL) {
			s = outds8(s);
			++tvslotcnt;
			}
		}
}
/*eject*/
wrt_tf_hdr()
{

/*
 * Output control and descriptor information obtained during PASS 1
 *
 * This information is of fixed length, and comes at the very beginning
 * of the transfer file
 */

	int length;

	fseek( trnfdes, 0L, 0 );

/*
 * Output the sizes of the lists built during PASS 1
 *
 *	1. symbol definition/undefinition
 *	2. MEMORY directives
 *	3. REGIONS directives
 *	4. input *.o and archive library files
 *	5. output sections
 *	6. assignment directives
 *	7. tv slot assignment directives
 */

	fwrite( &symcnt, sizeof(int), 1, trnfdes );
	fwrite( &memcnt, sizeof(int), 1, trnfdes );
	fwrite( &regcnt, sizeof(int), 1, trnfdes );
	fwrite( &ldfcnt, sizeof(int), 1, trnfdes );
	fwrite( &bldcnt, sizeof(int), 1, trnfdes );
	fwrite( &expcnt, sizeof(int), 1, trnfdes );
	fwrite(&tvslotcnt, sizeof(int), 1, trnfdes);

/*
 * Output the ld control flags
 */

	fwrite( &aflag, sizeof(char), 1, trnfdes );
	fwrite( &cflag, sizeof(char), 1, trnfdes );
	fwrite( &dflag, sizeof(char), 1, trnfdes );
	fwrite( &iflag, sizeof(char), 1, trnfdes );
	fwrite( &mflag, sizeof(char), 1, trnfdes );
	fwrite( &rflag, sizeof(char), 1, trnfdes );
	fwrite( &sflag, sizeof(char), 1, trnfdes );
	fwrite( &tvflag, sizeof(char), 1, trnfdes );
	fwrite( &Hflag, sizeof(char), 1, trnfdes );
	fwrite( &Nflag, sizeof(char), 1, trnfdes );
	fwrite( &Sflag, sizeof(char), 1, trnfdes );
	fwrite( &Vflag, sizeof(char), 1, trnfdes );
	fwrite( &Xflag, sizeof(char), 1, trnfdes );
	fwrite( &hflag, sizeof(int), 1, trnfdes );
	fwrite( &pflag, sizeof(int), 1, trnfdes );
	fwrite( &Bflag, sizeof(int), 1, trnfdes );
	fwrite( &VSflag, sizeof(short), 1, trnfdes);
#if UNIX || XL
	fwrite( &xflag, sizeof(char), 1, trnfdes );
#endif
#if COMMON
	fwrite( &tflag, sizeof(char), 1, trnfdes );
	fwrite( &Mflag, sizeof(char), 1, trnfdes );
#endif
#if PAGING
	fwrite( &Fflag, sizeof(char), 1, trnfdes );
#endif
#if PAGING || UNIX
	fwrite( &zflag, sizeof(char), 1, trnfdes );
#endif
#if ILDOPT
	fwrite( &ildflag, sizeof(char), 1, trnfdes );
#endif

/*
 * Output various values extracted from the parse
 */

	fwrite( &globfill, sizeof(short), 1, trnfdes );
	fwrite( &magic, sizeof(unsigned short), 1, trnfdes );

	fwrite( outfilnm, 128, 1, trnfdes );
	fwrite( epsymbol, 8, 1, trnfdes );

	/* convert filename from ptr to index */
	if (tvspec.tvinflnm != NULL)
		tvspec.tvinflnm = (char *) ((int) tvspec.tvinflnm - (int) strbase);
	fwrite( &tvspec, sizeof(TVINFO), 1, trnfdes );

/*
 * Output the size of the saved strings
 */

	length = strnext - strbase;
	fwrite( &length, sizeof(int), 1, trnfdes );
}
/*eject*/
MEMTYPE *
outds1(m)
MEMTYPE *m;
{

/*
 * Output one MEMTYPE data structure
 */

	fwrite( m, 1, sizeof(MEMTYPE), trnfdes );

	return( m->mtnext );
}



REGION *
outds2(r)
REGION *r;
{

/*
 * Output one REGION data structure
 */

	fwrite( r, 1, sizeof(REGION), trnfdes );

	return( r->rgnext );
}
/*eject*/
ACTITEM *
outds3(a)
ACTITEM *a;
{

/*
 * Output one AILDFILE, AILDLBRY, AIADFILE, or AIDFNSYM data structure
 *
 * Convert a "pointer to a string" to a "index to a string"
 */

	a->ldlbry.aiinflnm = (char *) ((int) a->ldlbry.aiinflnm - (int) strbase);
	a->ldlbry.aifilnam = (char *) ((int) a->ldlbry.aifilnam - (int) strbase);

	fwrite( a, 1, sizeof(ACTITEM), trnfdes );

	return( a->ldlbry.ainext );
}



ACTITEM *
outds4(a)
ACTITEM *a;
{

/*
 * Output one AIDFNSCN or AIDFNGRP data structure
 *
 * Convert a "pointer to a string" to a "index to a string"
 */

	register ACTITEM *anext, *b;
	ACTITEM *outds5();

	anext = a->dfnscn.ainext;
	a->dfnscn.aiinflnm = (char *) ((int) a->dfnscn.aiinflnm - (int) strbase);

	fwrite( a, 1, sizeof(ACTITEM), trnfdes );

	b = (ACTITEM *) a->dfnscn.sectspec.head;
	switch( a->dfnscn.aitype ) {
	case AIDFNSCN:
		while( b )
			switch( b->addscn.aitype ) {
			case AIADDSCN:
				b = outds5(b);
				break;
			case AIADFILE:
				b = outds3(b);
				break;
			case AIEVEXPR:
				b = outds6(b);
				break;
			}
		break;
	case AIDFNGRP:
		while( b )
			b = outds4(b);
		break;
	default:
		lderror(2,0,NULL,"failure dumping an AIDFNxxx data structure\n");
	}

	return( a->dfnscn.ainext );
}



ACTITEM *
outds5(a)
ACTITEM *a;
{

/*
 * Output one AIADDSCN data structure
 *
 * Convert a "pointer to a string" to a "index to a string"
 */

	a->addscn.aiinflnm = (char *) ((int) a->addscn.aiinflnm - (int) strbase);
	a->addscn.aiscfile = (char *) ((int) a->addscn.aiscfile - (int) strbase);

	fwrite( a, 1, sizeof(ACTITEM), trnfdes );

	return( a->addscn.ainext );
}



ACTITEM *
outds6(a)
ACTITEM *a;
{

/*
 * Output one AIEVEXPR data structure
 *
 * Convert a "pointer to a string" to a "index to a string"
 */

	a->evexpr.aiinflnm = (char *) ((int) a->evexpr.aiinflnm - (int) strbase);

	fwrite( a, 1, sizeof(ACTITEM), trnfdes );

	outds7( a->evexpr.aiexptr );

	return( a->evexpr.ainext );
}



outds7(e)
ENODE *e;
{

/*
 * Output one ENODE data structure
 */

	switch( (unsigned) e->gnode.exop ) {
	case INT:
	case DOT:
		fwrite( e, 1, sizeof(ENODE), trnfdes );
		break;
	case NAME:
		fwrite( e, 1, sizeof(ENODE), trnfdes );
		break;
	default:
		fwrite( e, 1, sizeof(ENODE), trnfdes );
		if( e->gnode.exleft )
			outds7(e->gnode.exleft);
		if( e->gnode.exright )
			outds7(e->gnode.exright);
	}

}



TVASSIGN *
outds8(s)
TVASSIGN *s;
{

/*
 *	Output one tv slot assignment (TVASSIGN) structure
 */

	fwrite( s, sizeof(TVASSIGN), 1, trnfdes);
	return( s->nxtslot );
}
#endif
