DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

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

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T a

⟦903fe8b97⟧ TextFile

    Length: 21519 (0x540f)
    Types: TextFile
    Names: »adlcomp.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Adl/adlcomp/adlcomp.c« 

TextFile

	/***************************************************************\
	*								*
	*	adlcomp.c - ADL compiler.  See the ADL documentation	*
	*	for information about ADL.				*
	*		Copyright 1987 by Ross Cunniff			*
	*								*
	\***************************************************************/

#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>

#include "adltypes.h"

#if UNIX
#  include <signal.h>
#endif

#include "adlprog.h"
#include "builtins.h"
#include "adldef.h"
#include "vstring.h"
#include "virtmem.h"
#include "adlcomp.h"

#define MAXDIR 4			/* Maximum number of -i dirs	*/

#if UNIX
char	*S_VAL = "adlsXXXXXX",		/* See below - patched		*/
	*CODE  = "adlcXXXXXX",		/* to use mktmp( 3 )		*/
	*tmpdir= "/tmp",		/* Default to /tmp		*/
	*PATH_SEPS = "/",		/* Set of path separators	*/
	*LAST_SEP = "/";		/* Final separator		*/
#endif

#if MSDOS
char	*S_VAL = "adlsval.tmp",		/* Temporary string file	*/
	*CODE  = "adlcode.tmp",		/* Temporary code file		*/
	*tmpdir= "",			/* Default to current dir	*/
	*PATH_SEPS = ":/\\",		/* Set of path separators	*/
	*LAST_SEP = "\\";		/* Final separator		*/
#endif

#if AMIGA
char
	*S_VAL = "adlsval.tmp",		/* Ditto above			*/
	*CODE  = "adlcode.tmp",		/* Ditto			*/
	*tmpdir= "RAM:",		/* Default to RAM:		*/
	*PATH_SEPS = ":/",		/* Set of path separators	*/
	*LAST_SEP = "/";		/* Final separator		*/
#endif

char	tmp_s[ 256 ],			/* Combined path and base	*/
	tmp_c[ 256 ],			/*   of CODE and S_VAL		*/
	*outname = "adlcomp.out",	/* Default output file name	*/
	*dirnames[MAXDIR];		/* -i names			*/

extern	char	*calloc();		/* Memory allocator		*/

struct	pagetab	codetab;		/* Structure for virtual code	*/

int16	NUM_VARS = 64,			/* Default # of ADL variables	*/
	NUM_ROUTS = 512,		/* Default # of ADL routines	*/
	NUM_OBJS = 256,			/* Default # of ADL objects	*/
	NUM_VERBS = 128,		/* Default # of ADL verbs	*/
	NUM_STR = 1024,			/* Default # of ADL strings	*/
	NUM_PREP = 8,			/* Default # of prep synonyms	*/
	NUM_VS = 8,			/* Default # of verb synonyms	*/

	numprep,			/* Actual # of prep synonyms	*/
	header,				/* Produce a status line?	*/
	debugging,			/* Retain symbols?		*/
	filenum,			/* String index of file name	*/
	numdir;				/* Number of -i dirs specified	*/

int	S_VAL_F,			/* String paging file		*/
	CODE_F;				/* Code paging file		*/

#if MSDOS
unsigned
    _stack = 10000;			/* Large default stack size	*/
#endif

	/***************************************************************\
	*								*
	*	main() - The main routine.  Opens files, initializes	*
	*	structures, compiles the code, writes the result.	*
	*	Pretty simple, no?					*
	*								*
	\***************************************************************/

main( argc, argv )
int	argc;
char	*argv[];
{
    getadlargs( argc, argv );		/* Get command line args	*/
    init();				/* Initialize structures	*/

    /* Print the copyright message */
    fputs( "ADL compiler - Version 3.2 - June 7, 1987\n", stderr );
    fputs( "Copyright 1985, 1986, 1987 by Ross Cunniff\n", stderr );
    fputs( "All rights reserved\n", stderr );
    fflush( stderr );

    adlcomp();				/* Compile the source		*/
    strcpy( token, "EOF" );		/* Indicate we're at EOF	*/
    write_code();			/* Write the code file		*/
    wrapup();				/* Close files			*/
    exit( numerr );			/* Return the number of errors	*/
}


	/***************************************************************\
	*								*
	*	getadlargs( argc, argv ) - extract meaning from		*
	*	the command line.  See the adlcomp man page for		*
	*	more information.					*
	*								*
	\***************************************************************/

getadlargs( argc, argv )
int	argc;
char	*argv[];
{
    int	i;
    char ch;
    char *getnext();

#if MSDOS
    argv[ 0 ] = "adlcomp";		/* MSDOS has no notion of argv[ 0 ] */
#endif

    if( argc < 2 )
	/* We must at least specify an input file */
	print_usage( argv[ 0 ] );

    /* Check each argument */
    for( i = 1; i < argc; i++ ) {
	if( *argv[ i ] == '-' ) {
	    ch = *++argv[ i ];
	    if( isupper( ch ) )
		ch = tolower( ch );
	    switch( ch ) {
		case 'e' : maxerr	= atoi( getnext( argv, &i ) );	break;
		case 'g' : NUM_VARS	= atoi( getnext( argv, &i ) );	break;
		case 'm' : NUM_STR	= atoi( getnext( argv, &i ) );	break;
		case 'n' : NUM_OBJS	= atoi( getnext( argv, &i ) );	break;
		case 'p' : NUM_PREP	= atoi( getnext( argv, &i ) );	break;
		case 'r' : NUM_ROUTS	= atoi( getnext( argv, &i ) );	break;
		case 's' : NUM_VS	= atoi( getnext( argv, &i ) );	break;
		case 'v' : NUM_VERBS	= atoi( getnext( argv, &i ) );	break;

		case 'i' : if( numdir >= MAXDIR )
			       fatal( "Too many -i options\n" );
			   dirnames[ numdir++ ] = getnext( argv, &i );
			   break;
		case 'o' : outname	=       getnext( argv, &i );	break;
		case 't' : tmpdir	=	getnext( argv, &i );	break;

		case 'w' : wignore	= 1;				break;
		case 'd' : debugging	= 1;				break;
		case 'h' : header	= 1;				break;

		default  : print_usage( argv[ 0 ] );
	    }
	}
	else if( *inname )
	    print_usage( argv[ 0 ] );
	else
	    strcpy( inname, argv[ i ] );
    }
    if( !*inname )
	print_usage( argv[ 0 ] );
}


	/***************************************************************\
	*								*
	*	print_usage( cname ) - print the USAGE error message	*
	*								*
	\***************************************************************/

print_usage( cname )
char
    *cname;
{
    fprintf( stderr, "Usage: %s Infile (with any of the following)\n", cname );
    fprintf( stderr, "	-o Outfile		File for output\n" );
    fprintf( stderr, "	-i Dir			Directory for INCLUDEs\n" );
    fprintf( stderr, "	-t Dir			Directory for temp files\n" );
    fprintf( stderr, "	-d			Output debugging info\n" );
    fprintf( stderr, "	-w			Suppress warnings\n" );
    fprintf( stderr, "	-e N			Max # of errors\n" );
    fprintf( stderr, "	-g N			Max # of globals\n" );
    fprintf( stderr, "	-m N			Max # of strings\n" );
    fprintf( stderr, "	-n N			Max # of objects\n" );
    fprintf( stderr, "	-p N			Max # of prep phrases\n" );
    fprintf( stderr, "	-r N			Max # of routines\n" );
    fprintf( stderr, "	-s N			Max # of verb phrases\n" );
    fprintf( stderr, "	-v N			Max # of verbs\n" );
    exit( 1 );
}


	/***************************************************************\
	*								*
	*	getnext( argv, indx ) - get the next string from	*
	*	argv, whether it be the rest of the current arg		*
	*	or the next arg.  This is to allow arguments like	*
	*	"-ifoo" and "-i foo" to be equivalent.			*
	*								*
	\***************************************************************/

char *
getnext( argv, indx )
char	*argv[];
int	*indx;
{
    if( *++argv[ *indx ] )
	return argv[ *indx ];
    else
	return argv[ ++*indx ];
}


	/***************************************************************\
	*								*
	*	init() - initialize the structures and files.		*
	*								*
	\***************************************************************/

init()
{
    /* Initialize the object sizes */
    hdr.nounindex.objsize	= sizeof( int16 );
    hdr.symindex.objsize	= sizeof( struct symbol );
    hdr.verbindex.objsize	= sizeof( struct verbrec );
    hdr.objindex.objsize	= sizeof( struct objrec );
    hdr.prepindex.objsize	= sizeof( struct preprec );
    hdr.vsindex.objsize		= sizeof( struct vp_syn );
    hdr.routindex.objsize	= sizeof( address );
    hdr.varindex.objsize	= sizeof( int16 );
    hdr.codeindex.objsize	= 512;
    hdr.strtabindex.objsize	= sizeof( int32 );
    hdr.strindex.objsize	= 512;
  
    /* Allocate space for the arrays */
    varspace	= (int16 *)	       calloc(hdr.varindex.objsize, NUM_VARS);
    routspace	= (address *)	       calloc(hdr.routindex.objsize,NUM_ROUTS);
    verbspace	= (struct verbrec *)   calloc(hdr.verbindex.objsize,NUM_VERBS);
    nounspace	= (int16 *)	       calloc(hdr.nounindex.objsize,NUM_OBJS);
    objspace	= (struct objrec *)    calloc(hdr.objindex.objsize, NUM_OBJS);
    prepspace	= (struct preprec *)   calloc(hdr.prepindex.objsize,NUM_PREP);
    verbsyn	= (struct vp_syn *)    calloc(hdr.vsindex.objsize,  NUM_VS);
    str_tab	= (int32 *)	       calloc(hdr.strtabindex.objsize,NUM_STR);

    /* Check the memory allocation */
    if(		(varspace	== (int16 *)		0)		||
		(routspace	== (address *)		0)		||
		(verbspace	== (struct verbrec *)	0)		||
		(objspace	== (struct objrec *)	0)		||
		(nounspace	== (int16 *)		0)		||
		(prepspace	== (struct preprec *)	0)		||
		(verbsyn	== (struct vp_syn *)	0)		||
		(str_tab	== (int32 *)		0)		)
	fatal( "Out of memory.\n" );

    /* Make the temporary names */
    mkpath( tmp_s, tmpdir, S_VAL );
    mkpath( tmp_c, tmpdir, CODE );

    /* Initialize the virtual code & string routines */
#if UNIX
    mktemp( tmp_s );
    mktemp( tmp_c );
#endif
    S_VAL_F = open( tmp_s, WB );
    CODE_F = open( tmp_c, WB );
    if( (S_VAL_F < 0) || (CODE_F < 0) )
	fatal( "Unable to open temporary files.\n" );

    vsinit( S_VAL_F, 0L, 0,(char *)NULL,(char *)NULL,(int16 *)NULL, str_tab );
    vm_init( CODE_F, 0L, &codetab, 1 );

    /* Set up some initial values */
    NUMOBJ = 2;				/* .ALL and STRING */
    NUMNOUN = 1;			/* Skip the null noun */
    NUMVERB = 2;			/* TELLER and NOVERB */
    NUMROUT = 4;			/* NULL, DWIMD, DWIMI, and START */
    numprep = 1;			/* Skip the null preposition */
    objspace[ _ALL ].cont = _STRING;

    /* Set up the input file */
    if( open_input( inname ) == 0 ) {
	fprintf( stderr, "Error opening input file %s\n", inname );
	exit( -1 );
    }
    filenum = newstr( inname );

    /* Initialize the dictionary */
    init_predefs();
}


	/***************************************************************\
	*								*
	*	breaker() - handle a signal				*
	*								*
	\***************************************************************/

breaker()
{
    printf( "***BREAK***\n" );
    close( S_VAL_F );	close( CODE_F );
    unlink( tmp_s );	unlink( tmp_c );
    exit( -1 );
}


	/***************************************************************\
	*								*
	*	adlcomp() - the heart of the compiler.  Reads tokens	*
	*	from the current input file, processing them until	*
	*	EOF or until the maximum number of errors has been	*
	*	exceeded.  Parsing is done with recursive descent.	*
	*								*
	\***************************************************************/

adlcomp()
{
    printf( "Reading from file %s\n", inname );
    fflush( stdout );
    while( 1 ) {
	lexer();			/* Read a token			*/
	if( t_type == EOF ) {
	    printf( "Done reading file %s\n", inname );
	    fflush( stdout );
	    return;
	}

	if( (t_type >= MIN_D) && (t_type <= MAX_D) )
	    /* This is one of PREP, ADJEC, etc.  Handle them generically */
	    getlist( t_type );
	else {
	    /* We need to special case the declaration. */
	    switch( t_type ) {
		case VAR_D	: getvars();		break;
		case NOUN_D	: getnouns();		break;
		case UNDECLARED	: getassign( 1 );	break;
		case INCLUDE	: getfile();		break;
		case MESSAGE	: printmsg();		break;
		case VERB	: getverb();		break;
		case ADJEC	:
		case NOUN	:
		case NOUN_SYN	: nounassign( 1, 0 );	break;
		case '('	: globassign();		break;
		case ROUTINE	: routassign();		break;
		case PREP	: prepassign();		break;
		default		: error( ILLEGAL_SYMBOL );
				  eatuntil( ';' );
	    }	/* switch */
	}	/* else */
    }		/* while */
}		/* adlcomp */


	/***************************************************************\
	*								*
	*	printmsg() - executes the MESSAGE directive, and	*
	*	prints a message on the user's terminal.		*
	*								*
	\***************************************************************/

printmsg()
{
    lexer();				/* Get a token.			*/
    if( t_type != STRING )
	_ERR_FIX( "Illegal compile time message.\n", ';' );
    fputs( token + 1, stderr );		/* Print the token.		*/
    fflush( stderr );
    lexer();
    if( t_type != ';' )			/* Expect a following semicolon	*/
	_ERR_FIX( SEMI_EXPECTED, ';' );
}


	/***************************************************************\
	*								*
	*	getfile() - handle the INCLUDE directive, reading	*
	*	from the appropriate file.				*
	*								*
	\***************************************************************/

getfile()
{
    char *fsave;
    char msg[ 80 ], nsave[ 512 ], t_in[ 512 ], *sprintf();
    int16 lsave, numsave, i, found;

    lexer();				/* Get a token.			*/
    if( t_type != STRING )
	_ERR_FIX( "File name expected for INCLUDE.\n", ';' );
    save_input( &fsave );		/* Save the current input file	*/
    strcpy( nsave, inname );		/* Save the current input name	*/
    lsave = numline;			/* Save the current line number	*/
    numsave = filenum;			/* Save the current file number	*/
    strcpy( inname, virtstr( t_val ) );	/* Get the rep. of the new name	*/
    filenum = t_val;			/* Get the new file number	*/
    numline = 1;			/* Set the new line number	*/

    /* Try to find the file in the current directory. */
    found = 0;
    if( open_input( inname ) == 0 ) {
	/* Couldn't find it.  Try to find it in the -i directories */
	for( i = 0; i < numdir; i++ ) {
	    mkpath( t_in, dirnames[ i ], inname );
	    if( open_input( t_in ) != 0 ) {
		found = 1;
		break;
	    }
	}
	if( !found ) {
	    sprintf( msg, "Error opening file \"%s\".\n", inname );
	    fatal( msg );
	}
	strcpy( inname, t_in );
    }
    adlcomp();			/* Recursively compile the new file.	*/
    close_input();		/* Close the file			*/
    restore_input( fsave );	/* Restore the old input file		*/
    numline = lsave;		/* Restore the old line number		*/
    strcpy( inname, nsave );	/* Restore the old file name		*/
    filenum = numsave;		/* Restore the old file number		*/
    lexer();			/* Get a token.				*/
    if( t_type != ';' )		/* Expect a ';' after the INCLUDE	*/
	_ERR_FIX( SEMI_EXPECTED, ';' );
}


mkpath( s, dir, base )
char
    *s,
    *dir,
    *base;
{
    int
	len,
	sep_found;
    char
	*check;

    /* Copy the directory name into the string */
    strcpy( s, dir );
    len = strlen( s ) - 1;

    /* Check to see if the name has a path separator at the end */
    check = PATH_SEPS;
    sep_found = 0;
    while( *check ) {
	if( s[ len ] == *check ) {
	    sep_found = 1;
	    break;
	}
	check++;
    }
    if( !sep_found )
	/* Add the separator */
	strcat( s, LAST_SEP );

    /* Concatenate the base name onto the string */
    strcat( s, base );
}


	/***************************************************************\
	*								*
	*	check_predefs() - check to see whether DWIMI, DWIMD,	*
	*	START, STRING, and TELLER have been defined.  Also,	*
	*	check the current number of various things against	*
	*	their maximum.						*
	*								*
	\***************************************************************/

check_predefs()
{
    if( !routspace[ _START ] )
	error( "START undefined.\n" );
    if( !routspace[ _DWIMI ] )
	warning( "DWIMI undefined.\n" );
    if( !routspace[ _DWIMD ] )
	warning( "DWIMD undefined.\n" );
    if( !objspace[ _STRING ].props[ _ACTION - 17 ] )
	warning( "STRING undefined.\n" );
    if( !(verbspace[ _TELLER ].preact||verbspace[ _TELLER ].postact) )
	warning( "TELLER undefined.\n" );
    if( !(verbspace[ _NOVERB ].preact||verbspace[ _NOVERB ].postact) )
	warning( "NOVERB undefined.\n" );
    checkmax( NUMVAR, NUM_VARS, "VARs" );
    checkmax( NUMROUT, NUM_ROUTS, "routines" );
    checkmax( NUMOBJ, NUM_OBJS, "objects" );
    checkmax( NUMVERB, NUM_VERBS, "verbs" );
    checkmax( NUMSTR, NUM_STR, "strings" );
    checkmax( NUMPP, NUM_PREP, "prep synonyms" );
    checkmax( NUMVS, NUM_VS, "[verb prep] synonyms" );
}

	/***************************************************************\
	*								*
	*	checkmax( n, max_n, name ) - checks n against max_n,	*
	*	and prints an appropriate message if n > max_n.		*
	*								*
	\***************************************************************/

checkmax( n, max_n, name )
int
    n, max_n;
char
    *name;
{
    printf( "%d out of %d %s used\n", n, max_n, name );
    fflush( stdout );
    if( n > max_n )
	error( "Number of %s is greater than %d!\n", name );
}


	/***************************************************************\
	*								*
	*	write_code() - write out the ADL executable.		*
	*								*
	\***************************************************************/

write_code()
{
    int outf;		/* The actual file being written		*/
    int32 temp;		/* Temporary area for long int calculations	*/
    int cmask;		/* Value of the umask call			*/
    int32 time();	/* Current time stamp.				*/

    /* Flush out all dirty pages to disk. */
    vsflush();
    vm_flush( &codetab );

    /* Tie up a few loose ends */
    hdr.strtabindex.numobjs = numstr();
    temp = currcode();
    hdr.codeindex.numobjs = (temp / 512L) + 1;
    temp = numchar();
    hdr.strindex.numobjs = (temp / 512L) + 1;

    /* Make sure all is OK */
    check_predefs();

    /* Don't write any code if errors were encountered. */
    if( numerr )
	return;

    /* Set up the file pointers */
    hdr.symindex.ptr	= sizeof( struct header );
    count_symtab( debugging );
    hdr.verbindex.ptr	= hdr.symindex.ptr    +
   				hdr.symindex.objsize    * NUMSYM;
    hdr.objindex.ptr	= hdr.verbindex.ptr   +
				hdr.verbindex.objsize   * NUMVERB;
    hdr.nounindex.ptr	= hdr.objindex.ptr +
				hdr.objindex.objsize	* NUMOBJ;
    hdr.varindex.ptr	= hdr.nounindex.ptr   +
				hdr.nounindex.objsize    * NUMNOUN;
    hdr.prepindex.ptr	= hdr.varindex.ptr    +
				hdr.varindex.objsize    * NUMVAR;
    hdr.vsindex.ptr	= hdr.prepindex.ptr   +
				hdr.prepindex.objsize	* NUMPP;
    hdr.routindex.ptr	= hdr.vsindex.ptr   +
				hdr.vsindex.objsize	* NUMVS;
    hdr.codeindex.ptr	= hdr.routindex.ptr   +
				hdr.routindex.objsize   * NUMROUT;
    hdr.strtabindex.ptr	= hdr.codeindex.ptr   +
				hdr.codeindex.numobjs   * 512;
    hdr.strindex.ptr	= hdr.strtabindex.ptr +
				hdr.strtabindex.objsize * NUMSTR;
  
    /* Set the timestamp and the magic number */
    hdr.adlid = time( 0 );
    hdr.magic = M_ADL;
    sprintf( hdr.adlname, "#! %s%s%s\n", ADL_NAME,
		   (header?" -h":"\0"),
		   (debugging?" -d":"\0") );

    /* Write the file */
    if( (outf = open( outname, WB )) < 0 )
	fatal( "Error writing to output file.\n" );
    adlstats();
    lseek( outf, 0L, 0 );
    write( outf, &hdr, sizeof( struct header ) );
    write_symtab( outf, debugging );
    writebuf( outf, verbspace,	&hdr.verbindex );
    writebuf( outf, objspace,	&hdr.objindex );
    writebuf( outf, nounspace,	&hdr.nounindex );
    writebuf( outf, varspace,	&hdr.varindex );
    writebuf( outf, prepspace,	&hdr.prepindex );
    writebuf( outf, verbsyn,	&hdr.vsindex );
    writebuf( outf, routspace,	&hdr.routindex );
    writestuff( CODE_F, outf,	&hdr.codeindex );
    writebuf( outf, str_tab, &hdr.strtabindex );
    writestuff( S_VAL_F, outf,	&hdr.strindex );

    /* Close the file */
    close( outf );

#if UNIX
    /* Make it executable */
    cmask = umask( 0 );
    (void)umask( cmask );
    chmod( outname, (0777 & (~cmask)) );
#endif
}


	/***************************************************************\
	*								*
	*	adlstats() - print some statistics about the		*
	*	compilation						*
	*								*
	\***************************************************************/

adlstats()
{
    int i;
    printf( "adlcomp %s -o %s ", inname, outname );
    printf( "-g %d -r %d ", NUMVAR+1, NUMROUT+1 );
    printf( "-v %d -n %d -m %d ", NUMVERB+1, NUMOBJ+1, NUMSTR+1 );
    printf( "-p %d -s %d%s%s", NUMPP, NUMVS,
		(wignore?" -w":""),(debugging?" -d":"") );

    for( i = 0; i < numdir; i++ )
	printf( " -i %s", dirnames[ i ] );
    printf( "\nWriting %ld bytes\n",
		hdr.strindex.ptr + 512*hdr.strindex.numobjs );
    fflush( stdout );
}


	/***************************************************************\
	*								*
	*	writebuf( f, b, d ) - write the buffer b to the file	*
	*	f, given the information in the header structure d.	*
	*								*
	\***************************************************************/

/*VARARGS 1*/
writebuf( f, b, d )
int	f;
char	*b;
struct	adldir	*d;
{
    lseek( f, 0L, 2 );				/* Seek to EOF		*/
    write( f, b, d->numobjs * d->objsize );	/* Write the data	*/
}


	/***************************************************************\
	*								*
	*	writestuff( ifile, ofile, dir ) - Copy data from	*
	*	ifile to ofile, according to the information in dir.	*
	*								*
	\***************************************************************/

writestuff( ifile, ofile, dir )
int	ifile, ofile;
struct	adldir	*dir;
{
    int32 t, i, n, r;
    char buf[ 512 ];

    t = dir->numobjs * dir->objsize;
    n = t / 512;			/* Write in 512 byte chunks	*/
    r = t % 512;			/* Number of remaining bytes	*/
    for( i = 0; i < n; i++ ) {
	lseek( ifile, (long)(i*512), 0 );
	read( ifile, buf, 512 );
	lseek( ofile, 0L, 2 );		/* Seek to EOF 			*/
	write( ofile, buf, 512 );
    }
    if( r ) {
	/* Write the remaining bytes */
	lseek( ifile, (long)(n*512), 0 );
	read( ifile, buf, 512 );
	lseek( ofile, 0L, 2 );		/* Seek to EOF			*/
	write( ofile, buf, 512 );
    }
    close( ifile );			/* Close the input file.	*/
}


	/***************************************************************\
	*								*
	*	wrapup() - clean up our mess and go home.		*
	*								*
	\***************************************************************/

wrapup()
{
    char *ep, *wp;

    /* Remove the temporary files. */
    unlink( tmp_s ); unlink( tmp_c );

    /* Print how many errors and warnings we've encountered. */
    ep = ( (numerr == 1) ? "" : "s" );
    wp = ( (numwarn == 1) ? "" : "s" );
    printf( "adlcomp complete. %d error%s, %d warning%s.\n", numerr, ep,
		numwarn, wp );
}

/*** EOF adlcomp.c ***/