🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.sources.mac
Article #61

Flex for the Mac (part 4 of 7)

#61
From: Earle R. Horton
Date: Fri, 01 Jul 1988 05:00
2121 lines
48686 bytes
[Flex for the Mac - part 4 of 7]

---
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	flex/misc.c
#	flex/nfa.c
#	flex/parse.y
#	flex/scan.l
# This archive created: Wed Jun 29 07:03:20 1988
# By:	Roger L. Long (bytebug@dhw68k.cts.com)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'misc.c'" '(10335 characters)'
if test -f 'misc.c'
then
	echo shar: will not over-write existing file "'misc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'misc.c'
X/* misc - miscellaneous flex routines */
X
X/*
X * Copyright (c) 1987, the University of California
X * 
X * The United States Government has rights in this work pursuant to
X * contract no. DE-AC03-76SF00098 between the United States Department of
X * Energy and the University of California.
X * 
X * This program may be redistributed.  Enhancements and derivative works
X * may be created provided the new works, if made available to the general
X * public, are made available for use by anyone.
X */
X
X#include <ctype.h>
X#include "flexdef.h"
X
Xchar *malloc(), *realloc();
X
X
X/* action_out - write the actions from the temporary file to lex.yy.c
X *
X * synopsis
X *     action_out();
X *
X *     Copies the action file up to %% (or end-of-file) to lex.yy.c
X */
X
Xaction_out()
X
X    {
X    char buf[MAXLINE];
X
X    while ( fgets( buf, MAXLINE, temp_action_file ) != NULL )
X	if ( buf[0] == '%' && buf[1] == '%' )
X	    break;
X	else
X	    fputs( buf, stdout );
X    }
X
X
X/* allocate_array - allocate memory for an integer array of the given size */
X
Xchar *allocate_array( size, element_size )
Xint size, element_size;
X
X    {
X    register char *mem = malloc( (unsigned) (element_size * size) );
X
X    if ( mem == NULL )
X	flexfatal( "memory allocation failed in allocate_array()" );
X
X    return ( mem );
X    }
X
X
X/* bubble - bubble sort an integer array in increasing order
X *
X * synopsis
X *   int v[n], n;
X *   bubble( v, n );
X *
X * description
X *   sorts the first n elements of array v and replaces them in
X *   increasing order.
X *
X * passed
X *   v - the array to be sorted
X *   n - the number of elements of 'v' to be sorted */
X
Xbubble( v, n )
Xint v[], n;
X
X    {
X    register int i, j, k;
X
X    for ( i = n; i > 1; --i )
X	for ( j = 1; j < i; ++j )
X	    if ( v[j] > v[j + 1] )	/* compare */
X		{
X		k = v[j];	/* exchange */
X		v[j] = v[j + 1];
X		v[j + 1] = k;
X		}
X    }
X
X
X/* clower - replace upper-case letter to lower-case
X *
X * synopsis:
X *    char clower(), c;
X *    c = clower( c );
X */
X
Xchar clower( c )
Xregister char c;
X
X    {
X    return ( isupper(c) ? tolower(c) : c );
X    }
X
X
X/* copy_string - returns a dynamically allocated copy of a string
X *
X * synopsis
X *    char *str, *copy, *copy_string();
X *    copy = copy_string( str );
X */
X
Xchar *copy_string( str )
Xregister char *str;
X
X    {
X    register char *c;
X    char *copy;
X
X    /* find length */
X    for ( c = str; *c; ++c )
X	;
X
X    copy = malloc( (unsigned) ((c - str + 1) * sizeof( char )) );
X
X    if ( copy == NULL )
X	flexfatal( "dynamic memory failure in copy_string()" );
X
X    for ( c = copy; (*c++ = *str++); )
X	;
X    
X    return ( copy );
X    }
X
X
X/* cshell - shell sort a character array in increasing order
X *
X * synopsis
X *
X *   char v[n];
X *   int n;
X *   cshell( v, n );
X *
X * description
X *   does a shell sort of the first n elements of array v.
X *
X * passed
X *   v - array to be sorted
X *   n - number of elements of v to be sorted
X */
Xcshell( v, n )
Xchar v[];
Xint n;
X
X    {
X    int gap, i, j, jg;
X    char k;
X
X    for ( gap = n / 2; gap > 0; gap = gap / 2 )
X	for ( i = gap; i < n; ++i )
X	    for ( j = i - gap; j >= 0; j = j - gap )
X		{
X		jg = j + gap;
X
X		if ( v[j] <= v[jg] )
X		    break;
X
X		k = v[j];
X		v[j] = v[jg];
X		v[jg] = k;
X		}
X    }
X
X
X/* dataend - finish up a block of data declarations
X *
X * synopsis
X *    dataend();
X */
Xdataend()
X
X    {
X    if ( datapos > 0 )
X	dataflush();
X
X    /* add terminator for initialization */
X    puts( "    } ;\n" );
X
X    dataline = 0;
X    }
X
X
X
X/* dataflush - flush generated data statements
X *
X * synopsis
X *    dataflush();
X */
Xdataflush()
X
X    {
X    putchar( '\n' );
X
X    if ( ++dataline >= NUMDATALINES )
X	{
X	/* put out a blank line so that the table is grouped into
X	 * large blocks that enable the user to find elements easily
X	 */
X	putchar( '\n' );
X	dataline = 0;
X	}
X
X    /* reset the number of characters written on the current line */
X    datapos = 0;
X    }
X
X/* gettime - return current time
X *
X * synopsis
X *    char *gettime(), *time_str;
X *    time_str = gettime();
X */
X#ifdef MPW
Xpascal void IUTIMESTRING(dateTime, wantSeconds, result)
X	long dateTime;
X	short wantSeconds;
X	char *result;
X	extern;
Xchar *p2cstr();
Xchar *gettime()
X
X    {
X	char *copy_string();
X	long curtime;
X	char strbuf[256];
X	GetDateTime(&curtime);
X	IUTIMESTRING(curtime,true,strbuf);
X	p2cstr(strbuf);
X	return (copy_string(strbuf));
X}
X
X#else
X/* include sys/types.h to use time_t and make lint happy */
X
X#include <sys/types.h>
X
Xchar *gettime()
X
X    {
X    time_t t, time();
X    char *result, *ctime(), *copy_string();
X
X    t = time( (long *) 0 );
X
X    result = copy_string( ctime( &t ) );
X
X    /* get rid of trailing newline */
X    result[24] = '\0';
X
X    return ( result );
X    }
X#endif
X
X/* lerrif - report an error message formatted with one integer argument
X *
X * synopsis
X *    char msg[];
X *    int arg;
X *    lerrif( msg, arg );
X */
X
Xlerrif( msg, arg )
Xchar msg[];
Xint arg;
X
X    {
X    char errmsg[MAXLINE];
X    (void) sprintf( errmsg, msg, arg );
X    flexerror( errmsg );
X    }
X
X
X/* lerrsf - report an error message formatted with one string argument
X *
X * synopsis
X *    char msg[], arg[];
X *    lerrsf( msg, arg );
X */
X
Xlerrsf( msg, arg )
Xchar msg[], arg[];
X
X    {
X    char errmsg[MAXLINE];
X
X    (void) sprintf( errmsg, msg, arg );
X    flexerror( errmsg );
X    }
X
X
X/* flexerror - report an error message and terminate
X *
X * synopsis
X *    char msg[];
X *    flexerror( msg );
X */
X
Xflexerror( msg )
Xchar msg[];
X
X    {
X    fprintf( stderr, "flex: %s\n", msg );
X    flexend( 1 );
X    }
X
X
X/* flexfatal - report a fatal error message and terminate
X *
X * synopsis
X *    char msg[];
X *    flexfatal( msg );
X */
X
Xflexfatal( msg )
Xchar msg[];
X
X    {
X    fprintf( stderr, "flex: fatal internal error %s\n", msg );
X    flexend( 1 );
X    }
X
X
X/* line_directive_out - spit out a "# line" statement */
X
Xline_directive_out( output_file_name )
XFILE *output_file_name;
X
X    {
X    if ( infilename && gen_line_dirs ) 
X        fprintf( output_file_name, "# line %d \"%s\"\n", linenum, infilename );
X    }
X
X
X/* mk2data - generate a data statement for a two-dimensional array
X *
X * synopsis
X *    int value;
X *    mk2data( value );
X *
X *  generates a data statement initializing the current 2-D array to "value"
X */
Xmk2data( value )
Xint value;
X
X    {
X    if ( datapos >= NUMDATAITEMS )
X	{
X	putchar( ',' );
X	dataflush();
X	}
X
X    if ( datapos == 0 )
X	/* indent */
X	fputs( "    ", stdout );
X
X    else
X	putchar( ',' );
X
X    ++datapos;
X
X    printf( "%5d", value );
X    }
X
X
X/* mkdata - generate a data statement
X *
X * synopsis
X *    int value;
X *    mkdata( value );
X *
X *  generates a data statement initializing the current array element to
X *  "value"
X */
Xmkdata( value )
Xint value;
X
X    {
X    if ( datapos >= NUMDATAITEMS )
X	{
X	putchar( ',' );
X	dataflush();
X	}
X
X    if ( datapos == 0 )
X	/* indent */
X	fputs( "    ", stdout );
X
X    else
X	putchar( ',' );
X
X    ++datapos;
X
X    printf( "%5d", value );
X    }
X
X
X/* myctoi - return the integer represented by a string of digits
X *
X * synopsis
X *    char array[];
X *    int val, myctoi();
X *    val = myctoi( array );
X *
X */
X
Xint myctoi( array )
Xchar array[];
X
X    {
X    int val = 0;
X
X    (void) sscanf( array, "%d", &val );
X
X    return ( val );
X    }
X
X
X/* myesc - return character corresponding to escape sequence
X *
X * synopsis
X *    char array[], c, myesc();
X *    c = myesc( array );
X *
X */
X
Xchar myesc( array )
Xchar array[];
X
X    {
X    switch ( array[1] )
X	{
X	case 'n': return ( '\n' );
X	case 't': return ( '\t' );
X	case 'f': return ( '\f' );
X	case 'r': return ( '\r' );
X	case 'b': return ( '\b' );
X
X	case '0':
X	    if ( isdigit(array[2]) )
X		{ /* \0<octal> */
X		char c, esc_char;
X		register int sptr = 2;
X
X		while ( isdigit(array[sptr]) )
X		    /* don't increment inside loop control because the
X		     * macro will expand it to two increments!  (Not a
X		     * problem with the C version of the macro)
X		     */
X		    ++sptr;
X
X		c = array[sptr];
X		array[sptr] = '\0';
X
X		esc_char = otoi( array + 2 );
X		array[sptr] = c;
X
X		if ( esc_char == '\0' )
X		    {
X		    synerr( "escape sequence for null not allowed" );
X		    return ( 1 );
X		    }
X
X		return ( esc_char );
X		}
X
X	    else
X		{
X		synerr( "escape sequence for null not allowed" );
X		return ( 1 );
X		}
X
X#ifdef NOTDEF
X	case '^':
X	    {
X	    register char next_char = array[2];
X
X	    if ( next_char == '?' )
X		return ( 0x7f );
X	    
X	    else if ( next_char >= 'A' && next_char <= 'Z' )
X		return ( next_char - 'A' + 1 );
X    
X	    else if ( next_char >= 'a' && next_char <= 'z' )
X		return ( next_char - 'z' + 1 );
X    
X	    synerr( "illegal \\^ escape sequence" );
X
X	    return ( 1 );
X	    }
X#endif
X	}
X    
X    return ( array[1] );
X    }
X
X
X/* otoi - convert an octal digit string to an integer value
X *
X * synopsis:
X *    int val, otoi();
X *    char str[];
X *    val = otoi( str );
X */
X
Xint otoi( str )
Xchar str[];
X
X    {
X#ifdef FTLSOURCE
X    fortran int gctoi()
X    int dummy = 1;
X
X    return ( gctoi( str, dummy, 8 ) );
X#else
X    int result;
X
X    (void) sscanf( str, "%o", &result );
X
X    return ( result );
X#endif
X    }
X
X
X
X
X/* reallocate_array - increase the size of a dynamic array */
X
Xchar *reallocate_array( array, size, element_size )
Xchar *array;
Xint size, element_size;
X
X    {
X    register char *new_array = realloc( array,
X					(unsigned) (size * element_size ));
X
X    if ( new_array == NULL )
X	flexfatal( "attempt to increase array size failed" );
X    
X    return ( new_array );
X    }
X
X
X/* skelout - write out one section of the skeleton file
X *
X * synopsis
X *    skelout();
X *
X * DESCRIPTION
X *    Copies from skelfile to stdout until a line beginning with "%%" or
X *    EOF is found.
X */
Xskelout()
X
X    {
X    char buf[MAXLINE];
X
X    while ( fgets( buf, MAXLINE, skelfile ) != NULL )
X	if ( buf[0] == '%' && buf[1] == '%' )
X	    break;
X	else
X	    fputs( buf, stdout );
X    }
X
X
X/* transition_struct_out - output a yy_trans_info structure
X *
X * synopsis
X *     int element_v, element_n;
X *     transition_struct_out( element_v, element_n );
X *
X * outputs the yy_trans_info structure with the two elements, element_v and
X * element_n.  Formats the output with spaces and carriage returns.
X */
X
Xtransition_struct_out( element_v, element_n )
Xint element_v, element_n;
X
X    {
X    printf( "%7d, %5d,", element_v, element_n );
X
X    datapos += TRANS_STRUCT_PRINT_LENGTH;
X
X    if ( datapos >= 75 )
X	{
X	printf( "\n" );
X
X	if ( ++dataline % 10 == 0 )
X	    printf( "\n" );
X
X	datapos = 0;
X	}
X    }
SHAR_EOF
if test 10335 -ne "`wc -c < 'misc.c'`"
then
	echo shar: error transmitting "'misc.c'" '(should have been 10335 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'nfa.c'" '(13633 characters)'
if test -f 'nfa.c'
then
	echo shar: will not over-write existing file "'nfa.c'"
else
sed 's/^X//' << \SHAR_EOF > 'nfa.c'
X/* nfa - NFA construction routines */
X
X/*
X * Copyright (c) 1987, the University of California
X * 
X * The United States Government has rights in this work pursuant to
X * contract no. DE-AC03-76SF00098 between the United States Department of
X * Energy and the University of California.
X * 
X * This program may be redistributed.  Enhancements and derivative works
X * may be created provided the new works, if made available to the general
X * public, are made available for use by anyone.
X */
X
X#include "flexdef.h"
X
X/* add_accept - add an accepting state to a machine
X *
X * synopsis
X *
X *   add_accept( mach, headcnt, trailcnt );
X *
X * the global ACCNUM is incremented and the new value becomes mach's
X * accepting number.  if headcnt or trailcnt is non-zero then the machine
X * recognizes a pattern with trailing context.  headcnt is the number of
X * characters in the matched part of the pattern, or zero if the matched
X * part has variable length.  trailcnt is the number of trailing context
X * characters in the pattern, or zero if the trailing context has variable
X * length.
X */
X
Xadd_accept( mach, headcnt, trailcnt )
Xint mach, headcnt, trailcnt;
X
X    {
X    int astate;
X
X    fprintf( temp_action_file, "case %d:\n", ++accnum );
X
X    if ( headcnt > 0 || trailcnt > 0 )
X	{ /* do trailing context magic to not match the trailing characters */
X	fprintf( temp_action_file,
X	    "YY_DO_BEFORE_SCAN; /* undo effects of setting up yytext */\n" );
X
X	if ( headcnt > 0 )
X	    {
X	    int head_offset = headcnt - 1;
X
X	    if ( fullspd || fulltbl )
X		/* with the fast skeleton, yy_c_buf_p points to the *next*
X		 * character to scan, rather than the one that was last
X		 * scanned
X		 */
X		++head_offset;
X
X	    if ( head_offset > 0 )
X		fprintf( temp_action_file, "yy_c_buf_p = yy_b_buf_p + %d;\n",
X			 head_offset );
X
X	    else
X		fprintf( temp_action_file, "yy_c_buf_p = yy_b_buf_p;\n" );
X	    }
X
X	else
X	    fprintf( temp_action_file, "yy_c_buf_p -= %d;\n", trailcnt );
X    
X	fprintf( temp_action_file, "YY_DO_BEFORE_ACTION; /* set up yytext again */\n" );
X	}
X
X    line_directive_out( temp_action_file );
X
X    /* hang the accepting number off an epsilon state.  if it is associated
X     * with a state that has a non-epsilon out-transition, then the state
X     * will accept BEFORE it makes that transition, i.e., one character
X     * too soon
X     */
X
X    if ( transchar[finalst[mach]] == SYM_EPSILON )
X	accptnum[finalst[mach]] = accnum;
X
X    else
X	{
X	astate = mkstate( SYM_EPSILON );
X	accptnum[astate] = accnum;
X	mach = link_machines( mach, astate );
X	}
X    }
X
X
X/* copysingl - make a given number of copies of a singleton machine
X *
X * synopsis
X *
X *   newsng = copysingl( singl, num );
X *
X *     newsng - a new singleton composed of num copies of singl
X *     singl  - a singleton machine
X *     num    - the number of copies of singl to be present in newsng
X */
X
Xint copysingl( singl, num )
Xint singl, num;
X
X    {
X    int copy, i;
X
X    copy = mkstate( SYM_EPSILON );
X
X    for ( i = 1; i <= num; ++i )
X	copy = link_machines( copy, dupmachine( singl ) );
X
X    return ( copy );
X    }
X
X
X/* dumpnfa - debugging routine to write out an nfa
X *
X * synopsis
X *    int state1;
X *    dumpnfa( state1 );
X */
X
Xdumpnfa( state1 )
Xint state1;
X
X    {
X    int sym, tsp1, tsp2, anum, ns;
X
X    fprintf( stderr, "\n\n********** beginning dump of nfa with start state %d\n",
X	     state1 );
X
X    /* we probably should loop starting at firstst[state1] and going to
X     * lastst[state1], but they're not maintained properly when we "or"
X     * all of the rules together.  So we use our knowledge that the machine
X     * starts at state 1 and ends at lastnfa.
X     */
X
X    /* for ( ns = firstst[state1]; ns <= lastst[state1]; ++ns ) */
X    for ( ns = 1; ns <= lastnfa; ++ns )
X	{
X	fprintf( stderr, "state # %4d\t", ns );
X
X	sym = transchar[ns];
X	tsp1 = trans1[ns];
X	tsp2 = trans2[ns];
X	anum = accptnum[ns];
X
X	fprintf( stderr, "%3d:  %4d, %4d", sym, tsp1, tsp2 );
X
X	if ( anum != NIL )
X	    fprintf( stderr, "  [%d]", anum );
X
X	fprintf( stderr, "\n" );
X	}
X
X    fprintf( stderr, "********** end of dump\n" );
X    }
X
X
X/* dupmachine - make a duplicate of a given machine
X *
X * synopsis
X *
X *   copy = dupmachine( mach );
X *
X *     copy - holds duplicate of mach
X *     mach - machine to be duplicated
X *
X * note that the copy of mach is NOT an exact duplicate; rather, all the
X * transition states values are adjusted so that the copy is self-contained,
X * as the original should have been.
X *
X * also note that the original MUST be contiguous, with its low and high
X * states accessible by the arrays firstst and lastst
X */
X
Xint dupmachine( mach )
Xint mach;
X
X    {
X    int i, state, init, last = lastst[mach], state_offset;
X
X    for ( i = firstst[mach]; i <= last; ++i )
X	{
X	state = mkstate( transchar[i] );
X
X	if ( trans1[i] != NO_TRANSITION )
X	    {
X	    mkxtion( finalst[state], trans1[i] + state - i );
X
X	    if ( transchar[i] == SYM_EPSILON && trans2[i] != NO_TRANSITION )
X		mkxtion( finalst[state], trans2[i] + state - i );
X	    }
X
X	accptnum[state] = accptnum[i];
X	}
X
X    state_offset = state - i + 1;
X
X    init = mach + state_offset;
X    firstst[init] = firstst[mach] + state_offset;
X    finalst[init] = finalst[mach] + state_offset;
X    lastst[init] = lastst[mach] + state_offset;
X
X    return ( init );
X    }
X
X
X/* link_machines - connect two machines together
X *
X * synopsis
X *
X *   new = link_machines( first, last );
X *
X *     new    - a machine constructed by connecting first to last
X *     first  - the machine whose successor is to be last
X *     last   - the machine whose predecessor is to be first
X *
X * note: this routine concatenates the machine first with the machine
X *  last to produce a machine new which will pattern-match first first
X *  and then last, and will fail if either of the sub-patterns fails.
X *  FIRST is set to new by the operation.  last is unmolested.
X */
X
Xint link_machines( first, last )
Xint first, last;
X
X    {
X    if ( first == NIL )
X	return ( last );
X
X    else if ( last == NIL )
X	return ( first );
X
X    else
X	{
X	mkxtion( finalst[first], last );
X	finalst[first] = finalst[last];
X	lastst[first] = max( lastst[first], lastst[last] );
X	firstst[first] = min( firstst[first], firstst[last] );
X
X	return ( first );
X	}
X    }
X
X
X/* mkbranch - make a machine that branches to two machines
X *
X * synopsis
X *
X *   branch = mkbranch( first, second );
X *
X *     branch - a machine which matches either first's pattern or second's
X *     first, second - machines whose patterns are to be or'ed (the | operator)
X *
X * note that first and second are NEITHER destroyed by the operation.  Also,
X * the resulting machine CANNOT be used with any other "mk" operation except
X * more mkbranch's.  Compare with mkor()
X */
X
Xint mkbranch( first, second )
Xint first, second;
X
X    {
X    int eps;
X
X    if ( first == NO_TRANSITION )
X	return ( second );
X
X    else if ( second == NO_TRANSITION )
X	return ( first );
X
X    eps = mkstate( SYM_EPSILON );
X
X    mkxtion( eps, first );
X    mkxtion( eps, second );
X
X    return ( eps );
X    }
X
X
X/* mkclos - convert a machine into a closure
X *
X * synopsis
X *   new = mkclos( state );
X *
X *     new - a new state which matches the closure of "state"
X */
X
Xint mkclos( state )
Xint state;
X
X    {
X    return ( mkopt( mkposcl( state ) ) );
X    }
X
X
X/* mkopt - make a machine optional
X *
X * synopsis
X *
X *   new = mkopt( mach );
X *
X *     new  - a machine which optionally matches whatever mach matched
X *     mach - the machine to make optional
X *
X * notes:
X *     1. mach must be the last machine created
X *     2. mach is destroyed by the call
X */
X
Xint mkopt( mach )
Xint mach;
X
X    {
X    int eps;
X
X    if ( ! SUPER_FREE_EPSILON(finalst[mach]) )
X	{
X	eps = mkstate( SYM_EPSILON );
X	mach = link_machines( mach, eps );
X	}
X
X    /* can't skimp on the following if FREE_EPSILON(mach) is true because
X     * some state interior to "mach" might point back to the beginning
X     * for a closure
X     */
X    eps = mkstate( SYM_EPSILON );
X    mach = link_machines( eps, mach );
X
X    mkxtion( mach, finalst[mach] );
X
X    return ( mach );
X    }
X
X
X/* mkor - make a machine that matches either one of two machines
X *
X * synopsis
X *
X *   new = mkor( first, second );
X *
X *     new - a machine which matches either first's pattern or second's
X *     first, second - machines whose patterns are to be or'ed (the | operator)
X *
X * note that first and second are both destroyed by the operation
X * the code is rather convoluted because an attempt is made to minimize
X * the number of epsilon states needed
X */
X
Xint mkor( first, second )
Xint first, second;
X
X    {
X    int eps, orend;
X
X    if ( first == NIL )
X	return ( second );
X
X    else if ( second == NIL )
X	return ( first );
X
X    else
X	{
X	/* see comment in mkopt() about why we can't use the first state
X	 * of "first" or "second" if they satisfy "FREE_EPSILON"
X	 */
X	eps = mkstate( SYM_EPSILON );
X
X	first = link_machines( eps, first );
X
X	mkxtion( first, second );
X
X	if ( SUPER_FREE_EPSILON(finalst[first]) &&
X	     accptnum[finalst[first]] == NIL )
X	    {
X	    orend = finalst[first];
X	    mkxtion( finalst[second], orend );
X	    }
X
X	else if ( SUPER_FREE_EPSILON(finalst[second]) &&
X		  accptnum[finalst[second]] == NIL )
X	    {
X	    orend = finalst[second];
X	    mkxtion( finalst[first], orend );
X	    }
X
X	else
X	    {
X	    eps = mkstate( SYM_EPSILON );
X
X	    first = link_machines( first, eps );
X	    orend = finalst[first];
X
X	    mkxtion( finalst[second], orend );
X	    }
X	}
X
X    finalst[first] = orend;
X    return ( first );
X    }
X
X
X/* mkposcl - convert a machine into a positive closure
X *
X * synopsis
X *   new = mkposcl( state );
X *
X *    new - a machine matching the positive closure of "state"
X */
X
Xint mkposcl( state )
Xint state;
X
X    {
X    int eps;
X
X    if ( SUPER_FREE_EPSILON(finalst[state]) )
X	{
X	mkxtion( finalst[state], state );
X	return ( state );
X	}
X
X    else
X	{
X	eps = mkstate( SYM_EPSILON );
X	mkxtion( eps, state );
X	return ( link_machines( state, eps ) );
X	}
X    }
X
X
X/* mkrep - make a replicated machine
X *
X * synopsis
X *   new = mkrep( mach, lb, ub );
X *
X *    new - a machine that matches whatever "mach" matched from "lb"
X *          number of times to "ub" number of times
X *
X * note
X *   if "ub" is INFINITY then "new" matches "lb" or more occurrences of "mach"
X */
X
Xint mkrep( mach, lb, ub )
Xint mach, lb, ub;
X
X    {
X    int base, tail, copy, i;
X
X    base = copysingl( mach, lb - 1 );
X
X    if ( ub == INFINITY )
X	{
X	copy = dupmachine( mach );
X	mach = link_machines( mach, link_machines( base, mkclos( copy ) ) );
X	}
X
X    else
X	{
X	tail = mkstate( SYM_EPSILON );
X
X	for ( i = lb; i < ub; ++i )
X	    {
X	    copy = dupmachine( mach );
X	    tail = mkopt( link_machines( copy, tail ) );
X	    }
X
X	mach = link_machines( mach, link_machines( base, tail ) );
X	}
X
X    return ( mach );
X    }
X
X
X/* mkstate - create a state with a transition on a given symbol
X *
X * synopsis
X *
X *   state = mkstate( sym );
X *
X *     state - a new state matching sym
X *     sym   - the symbol the new state is to have an out-transition on
X *
X * note that this routine makes new states in ascending order through the
X * state array (and increments LASTNFA accordingly).  The routine DUPMACHINE
X * relies on machines being made in ascending order and that they are
X * CONTIGUOUS.  Change it and you will have to rewrite DUPMACHINE (kludge
X * that it admittedly is)
X */
X
Xint mkstate( sym )
Xint sym;
X
X    {
X    if ( ++lastnfa >= current_mns )
X	{
X	if ( (current_mns += MNS_INCREMENT) >= MAXIMUM_MNS )
X	    lerrif( "input rules are too complicated (>= %d NFA states)",
X		    current_mns );
X	
X	++num_reallocs;
X
X	transchar = reallocate_integer_array( transchar, current_mns );
X	trans1 = reallocate_integer_array( trans1, current_mns );
X	trans2 = reallocate_integer_array( trans2, current_mns );
X	accptnum = reallocate_integer_array( accptnum, current_mns );
X	firstst = reallocate_integer_array( firstst, current_mns );
X	finalst = reallocate_integer_array( finalst, current_mns );
X	lastst = reallocate_integer_array( lastst, current_mns );
X	}
X
X    transchar[lastnfa] = sym;
X    trans1[lastnfa] = NO_TRANSITION;
X    trans2[lastnfa] = NO_TRANSITION;
X    accptnum[lastnfa] = NIL;
X    firstst[lastnfa] = lastnfa;
X    finalst[lastnfa] = lastnfa;
X    lastst[lastnfa] = lastnfa;
X
X    /* fix up equivalence classes base on this transition.  Note that any
X     * character which has its own transition gets its own equivalence class.
X     * Thus only characters which are only in character classes have a chance
X     * at being in the same equivalence class.  E.g. "a|b" puts 'a' and 'b'
X     * into two different equivalence classes.  "[ab]" puts them in the same
X     * equivalence class (barring other differences elsewhere in the input).
X     */
X
X    if ( sym < 0 )
X	{
X	/* we don't have to update the equivalence classes since that was
X	 * already done when the ccl was created for the first time
X	 */
X	}
X
X    else if ( sym == SYM_EPSILON )
X	++numeps;
X
X    else
X	{
X	if ( useecs )
X	    mkechar( sym, nextecm, ecgroup );
X	}
X
X    return ( lastnfa );
X    }
X
X
X/* mkxtion - make a transition from one state to another
X *
X * synopsis
X *
X *   mkxtion( statefrom, stateto );
X *
X *     statefrom - the state from which the transition is to be made
X *     stateto   - the state to which the transition is to be made
X */
X
Xmkxtion( statefrom, stateto )
Xint statefrom, stateto;
X
X    {
X    if ( trans1[statefrom] == NO_TRANSITION )
X	trans1[statefrom] = stateto;
X
X    else if ( (transchar[statefrom] != SYM_EPSILON) ||
X	      (trans2[statefrom] != NO_TRANSITION) )
X	flexfatal( "found too many transitions in mkxtion()" );
X
X    else
X	{ /* second out-transition for an epsilon state */
X	++eps2;
X	trans2[statefrom] = stateto;
X	}
X    }
SHAR_EOF
if test 13633 -ne "`wc -c < 'nfa.c'`"
then
	echo shar: error transmitting "'nfa.c'" '(should have been 13633 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'parse.y'" '(8970 characters)'
if test -f 'parse.y'
then
	echo shar: will not over-write existing file "'parse.y'"
else
sed 's/^X//' << \SHAR_EOF > 'parse.y'
X/* parse.y - parser for flex input */
X
X/*
X * Copyright (c) 1987, the University of California
X * 
X * The United States Government has rights in this work pursuant to
X * contract no. DE-AC03-76SF00098 between the United States Department of
X * Energy and the University of California.
X * 
X * This program may be redistributed.  Enhancements and derivative works
X * may be created provided the new works, if made available to the general
X * public, are made available for use by anyone.
X */
X
X%token CHAR NUMBER SECTEND SCDECL XSCDECL WHITESPACE NAME PREVCCL
X
X%{
X#include "flexdef.h"
X
Xint pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, actvp, rulelen;
Xint trlcontxt, xcluflg, cclsorted, varlength;
Xchar clower();
X
Xstatic int madeany = false;  /* whether we've made the '.' character class */
X
X%}
X
X%%
Xgoal            :  initlex sect1 sect1end sect2
X		;
X
Xinitlex         :
X			{
X			/* initialize for processing rules */
X
X			/* create default DFA start condition */
X			scinstal( "INITIAL", false );
X			}
X		;
X			
Xsect1		:  sect1 startconddecl WHITESPACE namelist1 '\n'
X		|
X		|  error '\n'
X			{ synerr( "unknown error processing section 1" ); }
X		;
X
Xsect1end	:  SECTEND
X		;
X
Xstartconddecl   :  SCDECL
X			{
X			/* these productions are separate from the s1object
X			 * rule because the semantics must be done before
X			 * we parse the remainder of an s1object
X			 */
X
X			xcluflg = false;
X			}
X		
X		|  XSCDECL
X			{ xcluflg = true; }
X		;
X
Xnamelist1	:  namelist1 WHITESPACE NAME
X			{ scinstal( nmstr, xcluflg ); }
X
X		|  NAME
X			{ scinstal( nmstr, xcluflg ); }
X
X		|  error
X                        { synerr( "bad start condition list" ); }
X		;
X
Xsect2           :  sect2 initforrule flexrule '\n'
X		|
X		;
X
Xinitforrule     :
X			{
X			/* initialize for a parse of one rule */
X			trlcontxt = varlength = false;
X			trailcnt = headcnt = rulelen = 0;
X			}
X		;
X
Xflexrule        :  scon '^' re eol 
X                        {
X			pat = link_machines( $3, $4 );
X			add_accept( pat, headcnt, trailcnt );
X
X			for ( i = 1; i <= actvp; ++i )
X			    scbol[actvsc[i]] = mkbranch( scbol[actvsc[i]], pat );
X			}
X
X		|  scon re eol 
X                        {
X			pat = link_machines( $2, $3 );
X			add_accept( pat, headcnt, trailcnt );
X
X			for ( i = 1; i <= actvp; ++i )
X			    scset[actvsc[i]] = mkbranch( scset[actvsc[i]], pat );
X			}
X
X                |  '^' re eol 
X			{
X			pat = link_machines( $2, $3 );
X			add_accept( pat, headcnt, trailcnt );
X
X			/* add to all non-exclusive start conditions,
X			 * including the default (0) start condition
X			 */
X
X			for ( i = 1; i <= lastsc; ++i )
X			    if ( ! scxclu[i] )
X				scbol[i] = mkbranch( scbol[i], pat );
X			}
X
X                |  re eol 
X			{
X			pat = link_machines( $1, $2 );
X			add_accept( pat, headcnt, trailcnt );
X
X			for ( i = 1; i <= lastsc; ++i )
X			    if ( ! scxclu[i] )
X				scset[i] = mkbranch( scset[i], pat );
X			}
X
X                |  error
X			{ synerr( "unrecognized rule" ); }
X		;
X
Xscon            :  '<' namelist2 '>'
X		;
X
Xnamelist2       :  namelist2 ',' NAME
X                        {
X			if ( (scnum = sclookup( nmstr )) == 0 )
X			    synerr( "undeclared start condition" );
X
X			else
X			    actvsc[++actvp] = scnum;
X			}
X
X		|  NAME
X			{
X			if ( (scnum = sclookup( nmstr )) == 0 )
X			    synerr( "undeclared start condition" );
X			else
X			    actvsc[actvp = 1] = scnum;
X			}
X
X		|  error
X			{ synerr( "bad start condition list" ); }
X		;
X
Xeol             :  '$'
X                        {
X			if ( trlcontxt )
X			    {
X			    synerr( "trailing context used twice" );
X			    $$ = mkstate( SYM_EPSILON );
X			    }
X			else
X			    {
X			    trlcontxt = true;
X
X			    if ( ! varlength )
X				headcnt = rulelen;
X
X			    ++rulelen;
X			    trailcnt = 1;
X
X			    eps = mkstate( SYM_EPSILON );
X			    $$ = link_machines( eps, mkstate( '\n' ) );
X			    }
X			}
X
X		|
X		        {
X		        $$ = mkstate( SYM_EPSILON );
X
X			if ( trlcontxt )
X			    {
X			    if ( varlength && headcnt == 0 )
X				/* both head and trail are variable-length */
X				synerr( "illegal trailing context" );
X
X			    else
X				trailcnt = rulelen;
X			    }
X		        }
X		;
X
Xre              :  re '|' series
X                        {
X			varlength = true;
X
X			$$ = mkor( $1, $3 );
X			}
X
X		|  re2 series
X			{ $$ = link_machines( $1, $2 ); }
X
X		|  series
X			{ $$ = $1; }
X		;
X
X
Xre2		:  re '/'
X			{
X			/* this rule is separate from the others for "re" so
X			 * that the reduction will occur before the trailing
X			 * series is parsed
X			 */
X
X			if ( trlcontxt )
X			    synerr( "trailing context used twice" );
X			else
X			    trlcontxt = true;
X
X			if ( varlength )
X			    /* the trailing context had better be fixed-length */
X			    varlength = false;
X			else
X			    headcnt = rulelen;
X
X			rulelen = 0;
X			$$ = $1;
X			}
X		;
X
Xseries          :  series singleton
X                        {
X			/* this is where concatenation of adjacent patterns
X			 * gets done
X			 */
X			$$ = link_machines( $1, $2 );
X			}
X
X		|  singleton
X			{ $$ = $1; }
X		;
X
Xsingleton       :  singleton '*'
X                        {
X			varlength = true;
X
X			$$ = mkclos( $1 );
X			}
X			
X		|  singleton '+'
X			{
X			varlength = true;
X
X			$$ = mkposcl( $1 );
X			}
X
X		|  singleton '?'
X			{
X			varlength = true;
X
X			$$ = mkopt( $1 );
X			}
X
X		|  singleton '{' NUMBER ',' NUMBER '}'
X			{
X			varlength = true;
X
X			if ( $3 > $5 || $3 <= 0 )
X			    {
X			    synerr( "bad iteration values" );
X			    $$ = $1;
X			    }
X			else
X			    $$ = mkrep( $1, $3, $5 );
X			}
X				
X		|  singleton '{' NUMBER ',' '}'
X			{
X			varlength = true;
X
X			if ( $3 <= 0 )
X			    {
X			    synerr( "iteration value must be positive" );
X			    $$ = $1;
X			    }
X
X			else
X			    $$ = mkrep( $1, $3, INFINITY );
X			}
X
X		|  singleton '{' NUMBER '}'
X			{
X			/* the singleton could be something like "(foo)",
X			 * in which case we have no idea what its length
X			 * is, so we punt here.
X			 */
X			varlength = true;
X
X			if ( $3 <= 0 )
X			    {
X			    synerr( "iteration value must be positive" );
X			    $$ = $1;
X			    }
X
X			else
X			    $$ = link_machines( $1, copysingl( $1, $3 - 1 ) );
X			}
X
X		|  '.'
X			{
X			if ( ! madeany )
X			    {
X			    /* create the '.' character class */
X			    anyccl = cclinit();
X			    ccladd( anyccl, '\n' );
X			    cclnegate( anyccl );
X
X			    if ( useecs )
X				mkeccl( ccltbl + cclmap[anyccl],
X					ccllen[anyccl], nextecm,
X					ecgroup, CSIZE );
X			    
X			    madeany = true;
X			    }
X
X			++rulelen;
X
X			$$ = mkstate( -anyccl );
X			}
X
X		|  fullccl
X			{
X			if ( ! cclsorted )
X			    /* sort characters for fast searching.  We use a
X			     * shell sort since this list could be large.
X			     */
X			    cshell( ccltbl + cclmap[$1], ccllen[$1] );
X
X			if ( useecs )
X			    mkeccl( ccltbl + cclmap[$1], ccllen[$1],
X				    nextecm, ecgroup, CSIZE );
X				     
X			++rulelen;
X
X			$$ = mkstate( -$1 );
X			}
X
X		|  PREVCCL
X			{
X			++rulelen;
X
X			$$ = mkstate( -$1 );
X			}
X
X		|  '"' string '"'
X			{ $$ = $2; }
X
X		|  '(' re ')'
X			{ $$ = $2; }
X
X		|  CHAR
X			{
X			++rulelen;
X
X			if ( $1 == '\0' )
X			    synerr( "null in rule" );
X
X			if ( caseins && $1 >= 'A' && $1 <= 'Z' )
X			    $1 = clower( $1 );
X
X			$$ = mkstate( $1 );
X			}
X		;
X
Xfullccl		:  '[' ccl ']'
X			{ $$ = $2; }
X
X		|  '[' '^' ccl ']'
X			{
X			/* *Sigh* - to be compatible Unix lex, negated ccls
X			 * match newlines
X			 */
X#ifdef NOTDEF
X			ccladd( $3, '\n' ); /* negated ccls don't match '\n' */
X			cclsorted = false; /* because we added the newline */
X#endif
X			cclnegate( $3 );
X			$$ = $3;
X			}
X		;
X
Xccl             :  ccl CHAR '-' CHAR
X                        {
X			if ( $2 > $4 )
X			    synerr( "negative range in character class" );
X
X			else
X			    {
X			    if ( caseins )
X				{
X				if ( $2 >= 'A' && $2 <= 'Z' )
X				    $2 = clower( $2 );
X				if ( $4 >= 'A' && $4 <= 'Z' )
X				    $4 = clower( $4 );
X				}
X
X			    for ( i = $2; i <= $4; ++i )
X			        ccladd( $1, i );
X
X			    /* keep track if this ccl is staying in alphabetical
X			     * order
X			     */
X			    cclsorted = cclsorted && ($2 > lastchar);
X			    lastchar = $4;
X			    }
X			
X			$$ = $1;
X			}
X
X		|  ccl CHAR
X		        {
X			if ( caseins )
X			    if ( $2 >= 'A' && $2 <= 'Z' )
X				$2 = clower( $2 );
X
X			ccladd( $1, $2 );
X			cclsorted = cclsorted && ($2 > lastchar);
X			lastchar = $2;
X			$$ = $1;
X			}
X
X		|
X			{
X			cclsorted = true;
X			lastchar = 0;
X			$$ = cclinit();
X			}
X		;
X
Xstring		:  string CHAR
X                        {
X			if ( caseins )
X			    if ( $2 >= 'A' && $2 <= 'Z' )
X				$2 = clower( $2 );
X
X			++rulelen;
X
X			$$ = link_machines( $1, mkstate( $2 ) );
X			}
X
X		|
X			{ $$ = mkstate( SYM_EPSILON ); }
X		;
X
X%%
X
X/* synerr - report a syntax error
X *
X * synopsis
X *    char str[];
X *    synerr( str );
X */
X
Xsynerr( str )
Xchar str[];
X
X    {
X    syntaxerror = true;
X#ifdef MPW
X	fprintf( stderr, "File %s ;Line %d # Syntax error: %s\n",infilename,linenum, str );
X#else
X    fprintf( stderr, "Syntax error at line %d:  %s\n", linenum, str );
X#endif
X    }
X
X
X/* yyerror - eat up an error message from the parser
X *
X * synopsis
X *    char msg[];
X *    yyerror( msg );
X */
X
Xyyerror( msg )
Xchar msg[];
X
X    {
X    }
SHAR_EOF
if test 8970 -ne "`wc -c < 'parse.y'`"
then
	echo shar: error transmitting "'parse.y'" '(should have been 8970 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'scan.l'" '(9222 characters)'
if test -f 'scan.l'
then
	echo shar: will not over-write existing file "'scan.l'"
else
sed 's/^X//' << \SHAR_EOF > 'scan.l'
X/* scan.l - scanner for flex input */
X
X/*
X * Copyright (c) 1987, the University of California
X * 
X * The United States Government has rights in this work pursuant to
X * contract no. DE-AC03-76SF00098 between the United States Department of
X * Energy and the University of California.
X * 
X * This program may be redistributed.  Enhancements and derivative works
X * may be created provided the new works, if made available to the general
X * public, are made available for use by anyone.
X */
X
X%{
X#include "flexdef.h"
X#include "parse.h"
X
X#define ACTION_ECHO fprintf( temp_action_file, "%s", yytext )
X#define MARK_END_OF_PROLOG fprintf( temp_action_file, "%%%% end of prolog\n" );
X
X#undef YY_DECL
X#define YY_DECL \
X	int flexscan()
X
X#define RETURNCHAR \
X	yylval = yytext[0] & BYTEMASK; \
X	return ( CHAR );
X
X#define RETURNNAME \
X	(void) strcpy( nmstr, yytext ); \
X	return ( NAME );
X
X#define PUT_BACK_STRING(str, start) \
X	for ( i = strlen( str ) - 1; i >= start; --i ) \
X	    unput(str[i])
X%}
X
X%x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE
X%x FIRSTCCL CCL ACTION RECOVER BRACEERROR C_COMMENT C_COMMENT_2 ACTION_COMMENT
X%x ACTION_STRING PERCENT_BRACE_ACTION
X
XWS		[ \t]+
X
XOPTWS		[ \t]*
X
XNAME		[a-z_][a-z_0-9]*
X
XSCNAME		{NAME}
X
XESCSEQ		\\([^^\n]|"^".|0[0-9]{1,3})
X
X%%
X    static int bracelevel, didadef;
X    int i, cclval;
X    char nmdef[MAXLINE], myesc();
X
X^{WS}.*\n		++linenum; ECHO; /* indented code */
X^#.*\n			++linenum; ECHO; /* treat as a comment */
X^"/*"			ECHO; BEGIN(C_COMMENT);
X^"%s"(tart)?		return ( SCDECL );
X^"%x"			return ( XSCDECL );
X^"%{".*\n		++linenum; line_directive_out( stdout ); BEGIN(CODEBLOCK);
X{WS}			return ( WHITESPACE );
X
X^"%%".*			{
X			sectnum = 2;
X			line_directive_out( stdout );
X			BEGIN(SECT2PROLOG);
X			return ( SECTEND );
X			}
X
X^"%"[^sx{%].*\n		{
X			fprintf( stderr,
X			     "old-style lex command at line %d ignored:\n\t%s",
X				 linenum, yytext );
X			++linenum;
X			}
X
X^{NAME}			{
X			(void) strcpy( nmstr, yytext );
X			didadef = false;
X			BEGIN(PICKUPDEF);
X			}
X
X{SCNAME}		RETURNNAME;
X^{OPTWS}\n		++linenum; /* allows blank lines in section 1 */
X\n			++linenum; return ( '\n' );
X.			synerr( "illegal character" ); BEGIN(RECOVER);
X
X
X<C_COMMENT>"*/"		ECHO; BEGIN(0);
X<C_COMMENT>"*/".*\n	++linenum; ECHO; BEGIN(0);
X<C_COMMENT>[^*\n]+	ECHO;
X<C_COMMENT>"*"		ECHO;
X<C_COMMENT>\n		++linenum; ECHO;
X
X<CODEBLOCK>^"%}".*\n	++linenum; BEGIN(0);
X<CODEBLOCK>.*\n		++linenum; ECHO;
X
X<PICKUPDEF>{WS}		/* separates name and definition */
X
X<PICKUPDEF>[^ \t\n].*	{
X			(void) strcpy( nmdef, yytext );
X
X			for ( i = strlen( nmdef ) - 1;
X			      i >= 0 &&
X			      nmdef[i] == ' ' || nmdef[i] == '\t';
X			      --i )
X			    ;
X
X			nmdef[i + 1] = '\0';
X
X                        ndinstal( nmstr, nmdef );
X			didadef = true;
X			}
X
X<PICKUPDEF>\n		{
X			if ( ! didadef )
X			    synerr( "incomplete name definition" );
X			BEGIN(0);
X			++linenum;
X			}
X
X<RECOVER>.*\n		++linenum; BEGIN(0); RETURNNAME;
X
X
X<SECT2PROLOG>.*\n/[^ \t\n]	{
X			++linenum;
X			ACTION_ECHO;
X			MARK_END_OF_PROLOG;
X			BEGIN(SECT2);
X			}
X
X<SECT2PROLOG>.*\n	++linenum; ACTION_ECHO;
X
X<SECT2>^{OPTWS}\n	++linenum; /* allow blank lines in section 2 */
X
X	/* this horrible mess of a rule matches indented lines which
X	 * do not contain "/*".  We need to make the distinction because
X	 * otherwise this rule will be taken instead of the rule which
X	 * matches the beginning of comments like this one
X	 */
X<SECT2>^{WS}([^/\n]|"/"[^*\n])*("/"?)\n	{
X			synerr( "indented code found outside of action" );
X			++linenum;
X			}
X
X<SECT2>"<"		BEGIN(SC); return ( '<' );
X<SECT2>^"^"		return ( '^' );
X<SECT2>\"		BEGIN(QUOTE); return ( '"' );
X<SECT2>"{"/[0-9]		BEGIN(NUM); return ( '{' );
X<SECT2>"{"[^0-9\n][^}\n]*	BEGIN(BRACEERROR);
X<SECT2>"$"/[ \t\n]	return ( '$' );
X
X<SECT2>{WS}"%{"		{
X			bracelevel = 1;
X			BEGIN(PERCENT_BRACE_ACTION);
X			return ( '\n' );
X			}
X<SECT2>{WS}"|".*\n	++linenum; return ( '\n' );
X
X<SECT2>^{OPTWS}"/*"	ACTION_ECHO; BEGIN(C_COMMENT_2);
X
X<SECT2>{WS}		{ /* needs to be separate from following rule due to
X			   * bug with trailing context
X			   */
X			bracelevel = 0;
X			BEGIN(ACTION);
X			return ( '\n' );
X			}
X
X<SECT2>{OPTWS}/\n	{
X			bracelevel = 0;
X			BEGIN(ACTION);
X			return ( '\n' );
X			}
X
X<SECT2>^{OPTWS}\n	++linenum; return ( '\n' );
X
X<SECT2>^"%%".*		{
X			/* guarantee that the SECT3 rule will have something
X			 * to match
X			 */
X			yyless(1);
X			sectnum = 3;
X			BEGIN(SECT3);
X			return ( EOF ); /* to stop the parser */
X			}
X
X<SECT2>"["([^\\\]\n]|{ESCSEQ})+"]"	{
X			(void) strcpy( nmstr, yytext );
X
X			/* check to see if we've already encountered this ccl */
X			if ( (cclval = ccllookup( nmstr )) )
X			    {
X			    yylval = cclval;
X			    ++cclreuse;
X			    return ( PREVCCL );
X			    }
X			else
X			    {
X			    /* we fudge a bit.  We know that this ccl will
X			     * soon be numbered as lastccl + 1 by cclinit
X			     */
X			    cclinstal( nmstr, lastccl + 1 );
X
X			    /* push back everything but the leading bracket
X			     * so the ccl can be rescanned
X			     */
X			    PUT_BACK_STRING(nmstr, 1);
X
X			    BEGIN(FIRSTCCL);
X			    return ( '[' );
X			    }
X			}
X
X<SECT2>"{"{NAME}"}"	{
X			register char *nmdefptr;
X			char *ndlookup();
X
X			(void) strcpy( nmstr, yytext );
X			nmstr[yyleng - 1] = '\0';  /* chop trailing brace */
X
X			/* lookup from "nmstr + 1" to chop leading brace */
X			if ( ! (nmdefptr = ndlookup( nmstr + 1 )) )
X			    synerr( "undefined {name}" );
X
X			else
X			    { /* push back name surrounded by ()'s */
X			    unput(')');
X			    PUT_BACK_STRING(nmdefptr, 0);
X			    unput('(');
X			    }
X			}
X
X<SECT2>[/|*+?.()]	return ( yytext[0] );
X<SECT2>.		RETURNCHAR;
X<SECT2>\n		++linenum; return ( '\n' );
X
X
X<SC>","			return ( ',' );
X<SC>">"			BEGIN(SECT2); return ( '>' );
X<SC>">"/"^"		BEGIN(CARETISBOL); return ( '>' );
X<SC>{SCNAME}		RETURNNAME;
X<SC>.			synerr( "bad start condition name" );
X
X<CARETISBOL>"^"		BEGIN(SECT2); return ( '^' );
X
X
X<QUOTE>[^"\n]		RETURNCHAR;
X<QUOTE>\"		BEGIN(SECT2); return ( '"' );
X
X<QUOTE>\n		{
X			synerr( "missing quote" );
X			BEGIN(SECT2);
X			++linenum;
X			return ( '"' );
X			}
X
X
X<FIRSTCCL>"^"/[^-\n]	BEGIN(CCL); return ( '^' );
X<FIRSTCCL>"^"/-		return ( '^' );
X<FIRSTCCL>-		BEGIN(CCL); yylval = '-'; return ( CHAR );
X<FIRSTCCL>.		BEGIN(CCL); RETURNCHAR;
X
X<CCL>-/[^\]\n]		return ( '-' );
X<CCL>[^\]\n]		RETURNCHAR;
X<CCL>"]"			BEGIN(SECT2); return ( ']' );
X
X
X<NUM>[0-9]+		{
X			yylval = myctoi( yytext );
X			return ( NUMBER );
X			}
X
X<NUM>","			return ( ',' );
X<NUM>"}"			BEGIN(SECT2); return ( '}' );
X
X<NUM>.			{
X			synerr( "bad character inside {}'s" );
X			BEGIN(SECT2);
X			return ( '}' );
X			}
X
X<NUM>\n			{
X			synerr( "missing }" );
X			BEGIN(SECT2);
X			++linenum;
X			return ( '}' );
X			}
X
X
X<BRACEERROR>"}"		synerr( "bad name in {}'s" ); BEGIN(SECT2);
X<BRACEERROR>\n		synerr( "missing }" ); ++linenum; BEGIN(SECT2);
X
X
X<PERCENT_BRACE_ACTION>{OPTWS}"%}".*	bracelevel = 0;
X<PERCENT_BRACE_ACTION>.*		ACTION_ECHO;
X<PERCENT_BRACE_ACTION>\n		{
X			++linenum;
X			ACTION_ECHO;
X			if ( bracelevel == 0 )
X			    {
X			    fputs( "\tYY_BREAK\n", temp_action_file );
X			    BEGIN(SECT2);
X			    }
X			}
X
X<ACTION>"{"		ACTION_ECHO; ++bracelevel;
X<ACTION>"}"		ACTION_ECHO; --bracelevel;
X<ACTION>[^{}"'/\n]+	ACTION_ECHO;
X<ACTION>"/*"		ACTION_ECHO; BEGIN(ACTION_COMMENT);
X<ACTION>"'"([^'\\\n]|\\.)*"'"	ACTION_ECHO; /* character constant */
X<ACTION>\"		ACTION_ECHO; BEGIN(ACTION_STRING);
X<ACTION>\n		{
X			++linenum;
X			ACTION_ECHO;
X			if ( bracelevel == 0 )
X			    {
X			    fputs( "\tYY_BREAK\n", temp_action_file );
X			    BEGIN(SECT2);
X			    }
X			}
X<ACTION>.		ACTION_ECHO;
X
X<ACTION_COMMENT>"*/"	ACTION_ECHO; BEGIN(ACTION);
X<ACTION_COMMENT>[^*\n]+	ACTION_ECHO;
X<ACTION_COMMENT>"*"	ACTION_ECHO;
X<ACTION_COMMENT>\n	++linenum; ACTION_ECHO;
X<ACTION_COMMENT>.	ACTION_ECHO;
X
X<C_COMMENT_2>"*/"	ACTION_ECHO; BEGIN(SECT2);
X<C_COMMENT_2>"*/".*\n	++linenum; ACTION_ECHO; BEGIN(SECT2);
X<C_COMMENT_2>[^*\n]+	ACTION_ECHO;
X<C_COMMENT_2>"*"	ACTION_ECHO;
X<C_COMMENT_2>\n		++linenum; ACTION_ECHO;
X
X<ACTION_STRING>[^"\\\n]+	ACTION_ECHO;
X<ACTION_STRING>\\.	ACTION_ECHO;
X<ACTION_STRING>\n	++linenum; ACTION_ECHO;
X<ACTION_STRING>\"	ACTION_ECHO; BEGIN(ACTION);
X<ACTION_STRING>.	ACTION_ECHO;
X
X
X<SECT2,QUOTE,CCL>{ESCSEQ}	{
X			yylval = myesc( yytext ) & BYTEMASK;
X			return ( CHAR );
X			}
X
X<FIRSTCCL>{ESCSEQ}	{
X			yylval = myesc( yytext ) & BYTEMASK;
X			BEGIN(CCL);
X			return ( CHAR );
X			}
X
X
X<SECT3>.|\n		{
X			register int numchars;
X
X			/* black magic - we know the names of a flex scanner's
X			 * internal variables.  We cap the input buffer with
X			 * an end-of-string and dump it to the output.
X			 */
X			YY_DO_BEFORE_SCAN; /* recover from setting up yytext */
X
X#ifdef FLEX_FAST_SKEL
X			fputs( yy_c_buf_p + 1, stdout );
X#else
X			yy_ch_buf[yy_e_buf_p + 1] = '\0';
X
X			/* ignore the first character; it's the second '%'
X			 * put back by the yyless(1) above
X			 */
X			fputs( yy_ch_buf + yy_c_buf_p + 1, stdout );
X#endif
X
X			/* if we don't do this, the data written by write()
X			 * can get overwritten when stdout is finally flushed
X			 */
X			(void) fflush( stdout );
X
X			while ( (numchars = read( fileno(yyin), yy_ch_buf,
X						  YY_BUF_MAX )) > 0 )
X			    (void) write( fileno(stdout), yy_ch_buf, numchars );
X	
X			if ( numchars < 0 )
X			    flexerror( "fatal read error in section 3" );
X
X			return ( EOF );
X			}
X%%
SHAR_EOF
if test 9222 -ne "`wc -c < 'scan.l'`"
then
	echo shar: error transmitting "'scan.l'" '(should have been 9222 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
--- end of part 4 ---
Technical Details
Message-ID: <9386@dhw68k.cts.com>
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!husc6!bloom-beacon!bu-cs!purdue!decwrl!hplabs!felix!dhw68k!macintosh
References: <9364@dhw68k.cts.com> <9368@dhw68k.cts.com> <9382@dhw68k.cts.com>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!husc6!bloom-beacon!bu-cs!purdue!decwrl!hplabs!felix!dhw68k!macintosh
From: earleh@eleazar.dartmouth.edu (Earle R. Horton)
Newsgroups: comp.sources.mac
Subject: Flex for the Mac (part 4 of 7)
Message-ID: <9386@dhw68k.cts.com>
Date: 1 Jul 88 05:00:34 GMT
References: <9364@dhw68k.cts.com> <9368@dhw68k.cts.com> <9382@dhw68k.cts.com>
Sender: macintosh@dhw68k.cts.com
Organization: Dartmouth College, Hanover, NH
Lines: 2121
Approved: bytebug@dhw68k.cts.com (Roger L. Long)