From earleh@eleazar.dartmouth.edu Fri Jul 1 00:00:34 1988 Path: utastro!ut-sally!cs.utexas.edu!tut.cis.ohio-state.edu!mailrus!ames!umd5!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) [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 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 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 */ 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"*/" ECHO; BEGIN(0); X"*/".*\n ++linenum; ECHO; BEGIN(0); X[^*\n]+ ECHO; X"*" ECHO; X\n ++linenum; ECHO; X X^"%}".*\n ++linenum; BEGIN(0); X.*\n ++linenum; ECHO; X X{WS} /* separates name and definition */ X X[^ \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\n { X if ( ! didadef ) X synerr( "incomplete name definition" ); X BEGIN(0); X ++linenum; X } X X.*\n ++linenum; BEGIN(0); RETURNNAME; X X X.*\n/[^ \t\n] { X ++linenum; X ACTION_ECHO; X MARK_END_OF_PROLOG; X BEGIN(SECT2); X } X X.*\n ++linenum; ACTION_ECHO; X X^{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^{WS}([^/\n]|"/"[^*\n])*("/"?)\n { X synerr( "indented code found outside of action" ); X ++linenum; X } X X"<" BEGIN(SC); return ( '<' ); X^"^" return ( '^' ); X\" BEGIN(QUOTE); return ( '"' ); X"{"/[0-9] BEGIN(NUM); return ( '{' ); X"{"[^0-9\n][^}\n]* BEGIN(BRACEERROR); X"$"/[ \t\n] return ( '$' ); X X{WS}"%{" { X bracelevel = 1; X BEGIN(PERCENT_BRACE_ACTION); X return ( '\n' ); X } X{WS}"|".*\n ++linenum; return ( '\n' ); X X^{OPTWS}"/*" ACTION_ECHO; BEGIN(C_COMMENT_2); X X{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{OPTWS}/\n { X bracelevel = 0; X BEGIN(ACTION); X return ( '\n' ); X } X X^{OPTWS}\n ++linenum; return ( '\n' ); X X^"%%".* { 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"["([^\\\]\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"{"{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[/|*+?.()] return ( yytext[0] ); X. RETURNCHAR; X\n ++linenum; return ( '\n' ); X X X"," return ( ',' ); X">" BEGIN(SECT2); return ( '>' ); X">"/"^" BEGIN(CARETISBOL); return ( '>' ); X{SCNAME} RETURNNAME; X. synerr( "bad start condition name" ); X X"^" BEGIN(SECT2); return ( '^' ); X X X[^"\n] RETURNCHAR; X\" BEGIN(SECT2); return ( '"' ); X X\n { X synerr( "missing quote" ); X BEGIN(SECT2); X ++linenum; X return ( '"' ); X } X X X"^"/[^-\n] BEGIN(CCL); return ( '^' ); X"^"/- return ( '^' ); X- BEGIN(CCL); yylval = '-'; return ( CHAR ); X. BEGIN(CCL); RETURNCHAR; X X-/[^\]\n] return ( '-' ); X[^\]\n] RETURNCHAR; X"]" BEGIN(SECT2); return ( ']' ); X X X[0-9]+ { X yylval = myctoi( yytext ); X return ( NUMBER ); X } X X"," return ( ',' ); X"}" BEGIN(SECT2); return ( '}' ); X X. { X synerr( "bad character inside {}'s" ); X BEGIN(SECT2); X return ( '}' ); X } X X\n { X synerr( "missing }" ); X BEGIN(SECT2); X ++linenum; X return ( '}' ); X } X X X"}" synerr( "bad name in {}'s" ); BEGIN(SECT2); X\n synerr( "missing }" ); ++linenum; BEGIN(SECT2); X X X{OPTWS}"%}".* bracelevel = 0; X.* ACTION_ECHO; X\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_ECHO; ++bracelevel; X"}" ACTION_ECHO; --bracelevel; X[^{}"'/\n]+ ACTION_ECHO; X"/*" ACTION_ECHO; BEGIN(ACTION_COMMENT); X"'"([^'\\\n]|\\.)*"'" ACTION_ECHO; /* character constant */ X\" ACTION_ECHO; BEGIN(ACTION_STRING); X\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_ECHO; X X"*/" ACTION_ECHO; BEGIN(ACTION); X[^*\n]+ ACTION_ECHO; X"*" ACTION_ECHO; X\n ++linenum; ACTION_ECHO; X. ACTION_ECHO; X X"*/" ACTION_ECHO; BEGIN(SECT2); X"*/".*\n ++linenum; ACTION_ECHO; BEGIN(SECT2); X[^*\n]+ ACTION_ECHO; X"*" ACTION_ECHO; X\n ++linenum; ACTION_ECHO; X X[^"\\\n]+ ACTION_ECHO; X\\. ACTION_ECHO; X\n ++linenum; ACTION_ECHO; X\" ACTION_ECHO; BEGIN(ACTION); X. ACTION_ECHO; X X X{ESCSEQ} { X yylval = myesc( yytext ) & BYTEMASK; X return ( CHAR ); X } X X{ESCSEQ} { X yylval = myesc( yytext ) & BYTEMASK; X BEGIN(CCL); X return ( CHAR ); X } X X X.|\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 ---