|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T a
Length: 21519 (0x540f) Types: TextFile Names: »adlcomp.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Adl/adlcomp/adlcomp.c«
/***************************************************************\ * * * 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 ***/