home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
001-099
/
ff091.lzh
/
adlcomp
/
adlcomp.c
next >
Wrap
C/C++ Source or Header
|
1987-07-08
|
22KB
|
716 lines
/***************************************************************\
* *
* 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 ***/