version 1.6, 2003/06/04 17:34:44 |
version 1.7, 2015/11/19 19:43:40 |
|
|
|
|
/* dfa - DFA construction routines */ |
/* dfa - DFA construction routines */ |
|
|
/*- |
/* Copyright (c) 1990 The Regents of the University of California. */ |
* Copyright (c) 1990 The Regents of the University of California. |
/* All rights reserved. */ |
* All rights reserved. |
|
* |
|
* This code is derived from software contributed to Berkeley by |
|
* Vern Paxson. |
|
* |
|
* The United States Government has rights in this work pursuant |
|
* to contract no. DE-AC03-76SF00098 between the United States |
|
* Department of Energy and the University of California. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* |
|
* Neither the name of the University nor the names of its contributors |
|
* may be used to endorse or promote products derived from this software |
|
* without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
* PURPOSE. |
|
*/ |
|
|
|
/* $Header$ */ |
/* This code is derived from software contributed to Berkeley by */ |
|
/* Vern Paxson. */ |
|
|
#include "flexdef.h" |
/* The United States Government has rights in this work pursuant */ |
|
/* to contract no. DE-AC03-76SF00098 between the United States */ |
|
/* Department of Energy and the University of California. */ |
|
|
|
/* Redistribution and use in source and binary forms, with or without */ |
|
/* modification, are permitted provided that the following conditions */ |
|
/* are met: */ |
|
|
|
/* 1. Redistributions of source code must retain the above copyright */ |
|
/* notice, this list of conditions and the following disclaimer. */ |
|
/* 2. Redistributions in binary form must reproduce the above copyright */ |
|
/* notice, this list of conditions and the following disclaimer in the */ |
|
/* documentation and/or other materials provided with the distribution. */ |
|
|
|
/* Neither the name of the University nor the names of its contributors */ |
|
/* may be used to endorse or promote products derived from this software */ |
|
/* without specific prior written permission. */ |
|
|
|
/* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */ |
|
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */ |
|
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ |
|
/* PURPOSE. */ |
|
|
|
#include "flexdef.h" |
|
#include "tables.h" |
|
|
/* declare functions that have forward references */ |
/* declare functions that have forward references */ |
|
|
void dump_associated_rules PROTO((FILE*, int)); |
void dump_associated_rules PROTO ((FILE *, int)); |
void dump_transitions PROTO((FILE*, int[])); |
void dump_transitions PROTO ((FILE *, int[])); |
void sympartition PROTO((int[], int, int[], int[])); |
void sympartition PROTO ((int[], int, int[], int[])); |
int symfollowset PROTO((int[], int, int, int[])); |
int symfollowset PROTO ((int[], int, int, int[])); |
|
|
|
|
/* check_for_backing_up - check a DFA state for backing up |
/* check_for_backing_up - check a DFA state for backing up |
|
|
* indexed by equivalence class. |
* indexed by equivalence class. |
*/ |
*/ |
|
|
void check_for_backing_up( ds, state ) |
void check_for_backing_up (ds, state) |
int ds; |
int ds; |
int state[]; |
int state[]; |
{ |
{ |
if ( (reject && ! dfaacc[ds].dfaacc_set) || |
if ((reject && !dfaacc[ds].dfaacc_set) || (!reject && !dfaacc[ds].dfaacc_state)) { /* state is non-accepting */ |
(! reject && ! dfaacc[ds].dfaacc_state) ) |
|
{ /* state is non-accepting */ |
|
++num_backing_up; |
++num_backing_up; |
|
|
if ( backing_up_report ) |
if (backing_up_report) { |
{ |
fprintf (backing_up_file, |
fprintf( backing_up_file, |
_("State #%d is non-accepting -\n"), ds); |
_( "State #%d is non-accepting -\n" ), ds ); |
|
|
|
/* identify the state */ |
/* identify the state */ |
dump_associated_rules( backing_up_file, ds ); |
dump_associated_rules (backing_up_file, ds); |
|
|
/* Now identify it further using the out- and |
/* Now identify it further using the out- and |
* jam-transitions. |
* jam-transitions. |
*/ |
*/ |
dump_transitions( backing_up_file, state ); |
dump_transitions (backing_up_file, state); |
|
|
putc( '\n', backing_up_file ); |
putc ('\n', backing_up_file); |
} |
|
} |
} |
} |
} |
|
} |
|
|
|
|
/* check_trailing_context - check to see if NFA state set constitutes |
/* check_trailing_context - check to see if NFA state set constitutes |
|
|
* accset[1 .. nacc] is the list of accepting numbers for the DFA state. |
* accset[1 .. nacc] is the list of accepting numbers for the DFA state. |
*/ |
*/ |
|
|
void check_trailing_context( nfa_states, num_states, accset, nacc ) |
void check_trailing_context (nfa_states, num_states, accset, nacc) |
int *nfa_states, num_states; |
int *nfa_states, num_states; |
int *accset; |
int *accset; |
int nacc; |
int nacc; |
{ |
{ |
int i, j; |
int i, j; |
|
|
for ( i = 1; i <= num_states; ++i ) |
for (i = 1; i <= num_states; ++i) { |
{ |
int ns = nfa_states[i]; |
int ns = nfa_states[i]; |
|
int type = state_type[ns]; |
int type = state_type[ns]; |
int ar = assoc_rule[ns]; |
int ar = assoc_rule[ns]; |
|
|
if ( type == STATE_NORMAL || rule_type[ar] != RULE_VARIABLE ) |
if (type == STATE_NORMAL || rule_type[ar] != RULE_VARIABLE) { /* do nothing */ |
{ /* do nothing */ |
} |
} |
|
|
|
else if ( type == STATE_TRAILING_CONTEXT ) |
else if (type == STATE_TRAILING_CONTEXT) { |
{ |
|
/* Potential trouble. Scan set of accepting numbers |
/* Potential trouble. Scan set of accepting numbers |
* for the one marking the end of the "head". We |
* for the one marking the end of the "head". We |
* assume that this looping will be fairly cheap |
* assume that this looping will be fairly cheap |
* since it's rare that an accepting number set |
* since it's rare that an accepting number set |
* is large. |
* is large. |
*/ |
*/ |
for ( j = 1; j <= nacc; ++j ) |
for (j = 1; j <= nacc; ++j) |
if ( accset[j] & YY_TRAILING_HEAD_MASK ) |
if (accset[j] & YY_TRAILING_HEAD_MASK) { |
{ |
line_warning (_ |
line_warning( |
("dangerous trailing context"), |
_( "dangerous trailing context" ), |
rule_linenum[ar]); |
rule_linenum[ar] ); |
|
return; |
return; |
} |
} |
} |
|
} |
} |
} |
} |
|
} |
|
|
|
|
/* dump_associated_rules - list the rules associated with a DFA state |
/* dump_associated_rules - list the rules associated with a DFA state |
|
|
* and writes a report to the given file. |
* and writes a report to the given file. |
*/ |
*/ |
|
|
void dump_associated_rules( file, ds ) |
void dump_associated_rules (file, ds) |
FILE *file; |
FILE *file; |
int ds; |
int ds; |
{ |
{ |
int i, j; |
int i, j; |
int num_associated_rules = 0; |
int num_associated_rules = 0; |
int rule_set[MAX_ASSOC_RULES + 1]; |
int rule_set[MAX_ASSOC_RULES + 1]; |
int *dset = dss[ds]; |
int *dset = dss[ds]; |
int size = dfasiz[ds]; |
int size = dfasiz[ds]; |
|
|
for ( i = 1; i <= size; ++i ) |
for (i = 1; i <= size; ++i) { |
{ |
|
int rule_num = rule_linenum[assoc_rule[dset[i]]]; |
int rule_num = rule_linenum[assoc_rule[dset[i]]]; |
|
|
for ( j = 1; j <= num_associated_rules; ++j ) |
for (j = 1; j <= num_associated_rules; ++j) |
if ( rule_num == rule_set[j] ) |
if (rule_num == rule_set[j]) |
break; |
break; |
|
|
if ( j > num_associated_rules ) |
if (j > num_associated_rules) { /* new rule */ |
{ /* new rule */ |
if (num_associated_rules < MAX_ASSOC_RULES) |
if ( num_associated_rules < MAX_ASSOC_RULES ) |
rule_set[++num_associated_rules] = |
rule_set[++num_associated_rules] = rule_num; |
rule_num; |
} |
|
} |
} |
|
} |
|
|
bubble( rule_set, num_associated_rules ); |
qsort (&rule_set [1], num_associated_rules, sizeof (rule_set [1]), intcmp); |
|
|
fprintf( file, _( " associated rule line numbers:" ) ); |
fprintf (file, _(" associated rule line numbers:")); |
|
|
for ( i = 1; i <= num_associated_rules; ++i ) |
for (i = 1; i <= num_associated_rules; ++i) { |
{ |
if (i % 8 == 1) |
if ( i % 8 == 1 ) |
putc ('\n', file); |
putc( '\n', file ); |
|
|
|
fprintf( file, "\t%d", rule_set[i] ); |
fprintf (file, "\t%d", rule_set[i]); |
} |
|
|
|
putc( '\n', file ); |
|
} |
} |
|
|
|
putc ('\n', file); |
|
} |
|
|
|
|
/* dump_transitions - list the transitions associated with a DFA state |
/* dump_transitions - list the transitions associated with a DFA state |
* |
* |
* synopsis |
* synopsis |
|
|
* is done to the given file. |
* is done to the given file. |
*/ |
*/ |
|
|
void dump_transitions( file, state ) |
void dump_transitions (file, state) |
FILE *file; |
FILE *file; |
int state[]; |
int state[]; |
{ |
{ |
int i, ec; |
int i, ec; |
int out_char_set[CSIZE]; |
int out_char_set[CSIZE]; |
|
|
for ( i = 0; i < csize; ++i ) |
for (i = 0; i < csize; ++i) { |
{ |
ec = ABS (ecgroup[i]); |
ec = ABS( ecgroup[i] ); |
|
out_char_set[i] = state[ec]; |
out_char_set[i] = state[ec]; |
} |
} |
|
|
fprintf( file, _( " out-transitions: " ) ); |
fprintf (file, _(" out-transitions: ")); |
|
|
list_character_set( file, out_char_set ); |
list_character_set (file, out_char_set); |
|
|
/* now invert the members of the set to get the jam transitions */ |
/* now invert the members of the set to get the jam transitions */ |
for ( i = 0; i < csize; ++i ) |
for (i = 0; i < csize; ++i) |
out_char_set[i] = ! out_char_set[i]; |
out_char_set[i] = !out_char_set[i]; |
|
|
fprintf( file, _( "\n jam-transitions: EOF " ) ); |
fprintf (file, _("\n jam-transitions: EOF ")); |
|
|
list_character_set( file, out_char_set ); |
list_character_set (file, out_char_set); |
|
|
putc( '\n', file ); |
putc ('\n', file); |
} |
} |
|
|
|
|
/* epsclosure - construct the epsilon closure of a set of ndfa states |
/* epsclosure - construct the epsilon closure of a set of ndfa states |
|
|
* hashval is the hash value for the dfa corresponding to the state set. |
* hashval is the hash value for the dfa corresponding to the state set. |
*/ |
*/ |
|
|
int *epsclosure( t, ns_addr, accset, nacc_addr, hv_addr ) |
int *epsclosure (t, ns_addr, accset, nacc_addr, hv_addr) |
int *t, *ns_addr, accset[], *nacc_addr, *hv_addr; |
int *t, *ns_addr, accset[], *nacc_addr, *hv_addr; |
{ |
{ |
int stkpos, ns, tsp; |
int stkpos, ns, tsp; |
int numstates = *ns_addr, nacc, hashval, transsym, nfaccnum; |
int numstates = *ns_addr, nacc, hashval, transsym, nfaccnum; |
int stkend, nstate; |
int stkend, nstate; |
static int did_stk_init = false, *stk; |
static int did_stk_init = false, *stk; |
|
|
#define MARK_STATE(state) \ |
#define MARK_STATE(state) \ |
trans1[state] = trans1[state] - MARKER_DIFFERENCE; |
do{ trans1[state] = trans1[state] - MARKER_DIFFERENCE;} while(0) |
|
|
#define IS_MARKED(state) (trans1[state] < 0) |
#define IS_MARKED(state) (trans1[state] < 0) |
|
|
#define UNMARK_STATE(state) \ |
#define UNMARK_STATE(state) \ |
trans1[state] = trans1[state] + MARKER_DIFFERENCE; |
do{ trans1[state] = trans1[state] + MARKER_DIFFERENCE;} while(0) |
|
|
#define CHECK_ACCEPT(state) \ |
#define CHECK_ACCEPT(state) \ |
{ \ |
do{ \ |
nfaccnum = accptnum[state]; \ |
nfaccnum = accptnum[state]; \ |
if ( nfaccnum != NIL ) \ |
if ( nfaccnum != NIL ) \ |
accset[++nacc] = nfaccnum; \ |
accset[++nacc] = nfaccnum; \ |
} |
}while(0) |
|
|
#define DO_REALLOCATION \ |
#define DO_REALLOCATION() \ |
{ \ |
do { \ |
current_max_dfa_size += MAX_DFA_SIZE_INCREMENT; \ |
current_max_dfa_size += MAX_DFA_SIZE_INCREMENT; \ |
++num_reallocs; \ |
++num_reallocs; \ |
t = reallocate_integer_array( t, current_max_dfa_size ); \ |
t = reallocate_integer_array( t, current_max_dfa_size ); \ |
stk = reallocate_integer_array( stk, current_max_dfa_size ); \ |
stk = reallocate_integer_array( stk, current_max_dfa_size ); \ |
} \ |
}while(0) \ |
|
|
#define PUT_ON_STACK(state) \ |
#define PUT_ON_STACK(state) \ |
{ \ |
do { \ |
if ( ++stkend >= current_max_dfa_size ) \ |
if ( ++stkend >= current_max_dfa_size ) \ |
DO_REALLOCATION \ |
DO_REALLOCATION(); \ |
stk[stkend] = state; \ |
stk[stkend] = state; \ |
MARK_STATE(state) \ |
MARK_STATE(state); \ |
} |
}while(0) |
|
|
#define ADD_STATE(state) \ |
#define ADD_STATE(state) \ |
{ \ |
do { \ |
if ( ++numstates >= current_max_dfa_size ) \ |
if ( ++numstates >= current_max_dfa_size ) \ |
DO_REALLOCATION \ |
DO_REALLOCATION(); \ |
t[numstates] = state; \ |
t[numstates] = state; \ |
hashval += state; \ |
hashval += state; \ |
} |
}while(0) |
|
|
#define STACK_STATE(state) \ |
#define STACK_STATE(state) \ |
{ \ |
do { \ |
PUT_ON_STACK(state) \ |
PUT_ON_STACK(state); \ |
CHECK_ACCEPT(state) \ |
CHECK_ACCEPT(state); \ |
if ( nfaccnum != NIL || transchar[state] != SYM_EPSILON ) \ |
if ( nfaccnum != NIL || transchar[state] != SYM_EPSILON ) \ |
ADD_STATE(state) \ |
ADD_STATE(state); \ |
} |
}while(0) |
|
|
|
|
if ( ! did_stk_init ) |
if (!did_stk_init) { |
{ |
stk = allocate_integer_array (current_max_dfa_size); |
stk = allocate_integer_array( current_max_dfa_size ); |
|
did_stk_init = true; |
did_stk_init = true; |
} |
} |
|
|
nacc = stkend = hashval = 0; |
nacc = stkend = hashval = 0; |
|
|
for ( nstate = 1; nstate <= numstates; ++nstate ) |
for (nstate = 1; nstate <= numstates; ++nstate) { |
{ |
|
ns = t[nstate]; |
ns = t[nstate]; |
|
|
/* The state could be marked if we've already pushed it onto |
/* The state could be marked if we've already pushed it onto |
* the stack. |
* the stack. |
*/ |
*/ |
if ( ! IS_MARKED(ns) ) |
if (!IS_MARKED (ns)) { |
{ |
PUT_ON_STACK (ns); |
PUT_ON_STACK(ns) |
CHECK_ACCEPT (ns); |
CHECK_ACCEPT(ns) |
|
hashval += ns; |
hashval += ns; |
} |
|
} |
} |
|
} |
|
|
for ( stkpos = 1; stkpos <= stkend; ++stkpos ) |
for (stkpos = 1; stkpos <= stkend; ++stkpos) { |
{ |
|
ns = stk[stkpos]; |
ns = stk[stkpos]; |
transsym = transchar[ns]; |
transsym = transchar[ns]; |
|
|
if ( transsym == SYM_EPSILON ) |
if (transsym == SYM_EPSILON) { |
{ |
|
tsp = trans1[ns] + MARKER_DIFFERENCE; |
tsp = trans1[ns] + MARKER_DIFFERENCE; |
|
|
if ( tsp != NO_TRANSITION ) |
if (tsp != NO_TRANSITION) { |
{ |
if (!IS_MARKED (tsp)) |
if ( ! IS_MARKED(tsp) ) |
STACK_STATE (tsp); |
STACK_STATE(tsp) |
|
|
|
tsp = trans2[ns]; |
tsp = trans2[ns]; |
|
|
if ( tsp != NO_TRANSITION && ! IS_MARKED(tsp) ) |
if (tsp != NO_TRANSITION |
STACK_STATE(tsp) |
&& !IS_MARKED (tsp)) |
} |
STACK_STATE (tsp); |
} |
} |
} |
} |
|
} |
|
|
/* Clear out "visit" markers. */ |
/* Clear out "visit" markers. */ |
|
|
for ( stkpos = 1; stkpos <= stkend; ++stkpos ) |
for (stkpos = 1; stkpos <= stkend; ++stkpos) { |
{ |
if (IS_MARKED (stk[stkpos])) |
if ( IS_MARKED(stk[stkpos]) ) |
UNMARK_STATE (stk[stkpos]); |
UNMARK_STATE(stk[stkpos]) |
|
else |
else |
flexfatal( |
flexfatal (_ |
_( "consistency check failed in epsclosure()" ) ); |
("consistency check failed in epsclosure()")); |
} |
} |
|
|
*ns_addr = numstates; |
*ns_addr = numstates; |
*hv_addr = hashval; |
*hv_addr = hashval; |
*nacc_addr = nacc; |
*nacc_addr = nacc; |
|
|
return t; |
return t; |
} |
} |
|
|
|
|
/* increase_max_dfas - increase the maximum number of DFAs */ |
/* increase_max_dfas - increase the maximum number of DFAs */ |
|
|
void increase_max_dfas() |
void increase_max_dfas () |
{ |
{ |
current_max_dfas += MAX_DFAS_INCREMENT; |
current_max_dfas += MAX_DFAS_INCREMENT; |
|
|
++num_reallocs; |
++num_reallocs; |
|
|
base = reallocate_integer_array( base, current_max_dfas ); |
base = reallocate_integer_array (base, current_max_dfas); |
def = reallocate_integer_array( def, current_max_dfas ); |
def = reallocate_integer_array (def, current_max_dfas); |
dfasiz = reallocate_integer_array( dfasiz, current_max_dfas ); |
dfasiz = reallocate_integer_array (dfasiz, current_max_dfas); |
accsiz = reallocate_integer_array( accsiz, current_max_dfas ); |
accsiz = reallocate_integer_array (accsiz, current_max_dfas); |
dhash = reallocate_integer_array( dhash, current_max_dfas ); |
dhash = reallocate_integer_array (dhash, current_max_dfas); |
dss = reallocate_int_ptr_array( dss, current_max_dfas ); |
dss = reallocate_int_ptr_array (dss, current_max_dfas); |
dfaacc = reallocate_dfaacc_union( dfaacc, current_max_dfas ); |
dfaacc = reallocate_dfaacc_union (dfaacc, current_max_dfas); |
|
|
if ( nultrans ) |
if (nultrans) |
nultrans = |
nultrans = |
reallocate_integer_array( nultrans, current_max_dfas ); |
reallocate_integer_array (nultrans, |
} |
current_max_dfas); |
|
} |
|
|
|
|
/* ntod - convert an ndfa to a dfa |
/* ntod - convert an ndfa to a dfa |
|
|
* dfa starts out in state #1. |
* dfa starts out in state #1. |
*/ |
*/ |
|
|
void ntod() |
void ntod () |
{ |
{ |
int *accset, ds, nacc, newds; |
int *accset, ds, nacc, newds; |
int sym, hashval, numstates, dsize; |
int sym, hashval, numstates, dsize; |
int num_full_table_rows; /* used only for -f */ |
int num_full_table_rows=0; /* used only for -f */ |
int *nset, *dset; |
int *nset, *dset; |
int targptr, totaltrans, i, comstate, comfreq, targ; |
int targptr, totaltrans, i, comstate, comfreq, targ; |
int symlist[CSIZE + 1]; |
int symlist[CSIZE + 1]; |
int num_start_states; |
int num_start_states; |
int todo_head, todo_next; |
int todo_head, todo_next; |
|
|
|
struct yytbl_data *yynxt_tbl = 0; |
|
flex_int32_t *yynxt_data = 0, yynxt_curr = 0; |
|
|
/* Note that the following are indexed by *equivalence classes* |
/* Note that the following are indexed by *equivalence classes* |
* and not by characters. Since equivalence classes are indexed |
* and not by characters. Since equivalence classes are indexed |
* beginning with 1, even if the scanner accepts NUL's, this |
* beginning with 1, even if the scanner accepts NUL's, this |
|
|
* equivalence class) these arrays must have room for indices |
* equivalence class) these arrays must have room for indices |
* from 1 to CSIZE, so their size must be CSIZE + 1. |
* from 1 to CSIZE, so their size must be CSIZE + 1. |
*/ |
*/ |
int duplist[CSIZE + 1], state[CSIZE + 1]; |
int duplist[CSIZE + 1], state[CSIZE + 1]; |
int targfreq[CSIZE + 1], targstate[CSIZE + 1]; |
int targfreq[CSIZE + 1], targstate[CSIZE + 1]; |
|
|
accset = allocate_integer_array( num_rules + 1 ); |
/* accset needs to be large enough to hold all of the rules present |
nset = allocate_integer_array( current_max_dfa_size ); |
* in the input, *plus* their YY_TRAILING_HEAD_MASK variants. |
|
*/ |
|
accset = allocate_integer_array ((num_rules + 1) * 2); |
|
nset = allocate_integer_array (current_max_dfa_size); |
|
|
/* The "todo" queue is represented by the head, which is the DFA |
/* The "todo" queue is represented by the head, which is the DFA |
* state currently being processed, and the "next", which is the |
* state currently being processed, and the "next", which is the |
|
|
*/ |
*/ |
todo_head = todo_next = 0; |
todo_head = todo_next = 0; |
|
|
for ( i = 0; i <= csize; ++i ) |
for (i = 0; i <= csize; ++i) { |
{ |
|
duplist[i] = NIL; |
duplist[i] = NIL; |
symlist[i] = false; |
symlist[i] = false; |
} |
} |
|
|
for ( i = 0; i <= num_rules; ++i ) |
for (i = 0; i <= num_rules; ++i) |
accset[i] = NIL; |
accset[i] = NIL; |
|
|
if ( trace ) |
if (trace) { |
{ |
dumpnfa (scset[1]); |
dumpnfa( scset[1] ); |
fputs (_("\n\nDFA Dump:\n\n"), stderr); |
fputs( _( "\n\nDFA Dump:\n\n" ), stderr ); |
} |
} |
|
|
|
inittbl(); |
inittbl (); |
|
|
/* Check to see whether we should build a separate table for |
/* Check to see whether we should build a separate table for |
* transitions on NUL characters. We don't do this for full-speed |
* transitions on NUL characters. We don't do this for full-speed |
|
|
/* Note that the test for ecgroup[0] == numecs below accomplishes |
/* Note that the test for ecgroup[0] == numecs below accomplishes |
* both (1) and (2) above |
* both (1) and (2) above |
*/ |
*/ |
if ( ! fullspd && ecgroup[0] == numecs ) |
if (!fullspd && ecgroup[0] == numecs) { |
{ |
|
/* NUL is alone in its equivalence class, which is the |
/* NUL is alone in its equivalence class, which is the |
* last one. |
* last one. |
*/ |
*/ |
int use_NUL_table = (numecs == csize); |
int use_NUL_table = (numecs == csize); |
|
|
if ( fulltbl && ! use_NUL_table ) |
if (fulltbl && !use_NUL_table) { |
{ |
|
/* We still may want to use the table if numecs |
/* We still may want to use the table if numecs |
* is a power of 2. |
* is a power of 2. |
*/ |
*/ |
int power_of_two; |
int power_of_two; |
|
|
for ( power_of_two = 1; power_of_two <= csize; |
for (power_of_two = 1; power_of_two <= csize; |
power_of_two *= 2 ) |
power_of_two *= 2) |
if ( numecs == power_of_two ) |
if (numecs == power_of_two) { |
{ |
|
use_NUL_table = true; |
use_NUL_table = true; |
break; |
break; |
} |
} |
} |
} |
|
|
if ( use_NUL_table ) |
if (use_NUL_table) |
nultrans = allocate_integer_array( current_max_dfas ); |
nultrans = |
|
allocate_integer_array (current_max_dfas); |
|
|
/* From now on, nultrans != nil indicates that we're |
/* From now on, nultrans != nil indicates that we're |
* saving null transitions for later, separate encoding. |
* saving null transitions for later, separate encoding. |
*/ |
*/ |
} |
} |
|
|
|
|
if ( fullspd ) |
if (fullspd) { |
{ |
for (i = 0; i <= numecs; ++i) |
for ( i = 0; i <= numecs; ++i ) |
|
state[i] = 0; |
state[i] = 0; |
|
|
place_state( state, 0, 0 ); |
place_state (state, 0, 0); |
dfaacc[0].dfaacc_state = 0; |
dfaacc[0].dfaacc_state = 0; |
} |
} |
|
|
else if ( fulltbl ) |
else if (fulltbl) { |
{ |
if (nultrans) |
if ( nultrans ) |
|
/* We won't be including NUL's transitions in the |
/* We won't be including NUL's transitions in the |
* table, so build it for entries from 0 .. numecs - 1. |
* table, so build it for entries from 0 .. numecs - 1. |
*/ |
*/ |
|
|
*/ |
*/ |
num_full_table_rows = numecs + 1; |
num_full_table_rows = numecs + 1; |
|
|
|
/* Begin generating yy_nxt[][] |
|
* This spans the entire LONG function. |
|
* This table is tricky because we don't know how big it will be. |
|
* So we'll have to realloc() on the way... |
|
* we'll wait until we can calculate yynxt_tbl->td_hilen. |
|
*/ |
|
yynxt_tbl = |
|
(struct yytbl_data *) calloc (1, |
|
sizeof (struct |
|
yytbl_data)); |
|
yytbl_data_init (yynxt_tbl, YYTD_ID_NXT); |
|
yynxt_tbl->td_hilen = 1; |
|
yynxt_tbl->td_lolen = num_full_table_rows; |
|
yynxt_tbl->td_data = yynxt_data = |
|
(flex_int32_t *) calloc (yynxt_tbl->td_lolen * |
|
yynxt_tbl->td_hilen, |
|
sizeof (flex_int32_t)); |
|
yynxt_curr = 0; |
|
|
|
buf_prints (&yydmap_buf, |
|
"\t{YYTD_ID_NXT, (void**)&yy_nxt, sizeof(%s)},\n", |
|
long_align ? "flex_int32_t" : "flex_int16_t"); |
|
|
/* Unless -Ca, declare it "short" because it's a real |
/* Unless -Ca, declare it "short" because it's a real |
* long-shot that that won't be large enough. |
* long-shot that that won't be large enough. |
*/ |
*/ |
out_str_dec( "static yyconst %s yy_nxt[][%d] =\n {\n", |
if (gentables) |
/* '}' so vi doesn't get too confused */ |
out_str_dec |
long_align ? "long" : "short", num_full_table_rows ); |
("static yyconst %s yy_nxt[][%d] =\n {\n", |
|
long_align ? "flex_int32_t" : "flex_int16_t", |
|
num_full_table_rows); |
|
else { |
|
out_dec ("#undef YY_NXT_LOLEN\n#define YY_NXT_LOLEN (%d)\n", num_full_table_rows); |
|
out_str ("static yyconst %s *yy_nxt =0;\n", |
|
long_align ? "flex_int32_t" : "flex_int16_t"); |
|
} |
|
|
outn( " {" ); |
|
|
|
/* Generate 0 entries for state #0. */ |
if (gentables) |
for ( i = 0; i < num_full_table_rows; ++i ) |
outn (" {"); |
mk2data( 0 ); |
|
|
|
dataflush(); |
/* Generate 0 entries for state #0. */ |
outn( " },\n" ); |
for (i = 0; i < num_full_table_rows; ++i) { |
|
mk2data (0); |
|
yynxt_data[yynxt_curr++] = 0; |
} |
} |
|
|
|
dataflush (); |
|
if (gentables) |
|
outn (" },\n"); |
|
} |
|
|
/* Create the first states. */ |
/* Create the first states. */ |
|
|
num_start_states = lastsc * 2; |
num_start_states = lastsc * 2; |
|
|
for ( i = 1; i <= num_start_states; ++i ) |
for (i = 1; i <= num_start_states; ++i) { |
{ |
|
numstates = 1; |
numstates = 1; |
|
|
/* For each start condition, make one state for the case when |
/* For each start condition, make one state for the case when |
* we're at the beginning of the line (the '^' operator) and |
* we're at the beginning of the line (the '^' operator) and |
* one for the case when we're not. |
* one for the case when we're not. |
*/ |
*/ |
if ( i % 2 == 1 ) |
if (i % 2 == 1) |
nset[numstates] = scset[(i / 2) + 1]; |
nset[numstates] = scset[(i / 2) + 1]; |
else |
else |
nset[numstates] = |
nset[numstates] = |
mkbranch( scbol[i / 2], scset[i / 2] ); |
mkbranch (scbol[i / 2], scset[i / 2]); |
|
|
nset = epsclosure( nset, &numstates, accset, &nacc, &hashval ); |
nset = epsclosure (nset, &numstates, accset, &nacc, |
|
&hashval); |
|
|
if ( snstods( nset, numstates, accset, nacc, hashval, &ds ) ) |
if (snstods (nset, numstates, accset, nacc, hashval, &ds)) { |
{ |
|
numas += nacc; |
numas += nacc; |
totnst += numstates; |
totnst += numstates; |
++todo_next; |
++todo_next; |
|
|
if ( variable_trailing_context_rules && nacc > 0 ) |
if (variable_trailing_context_rules && nacc > 0) |
check_trailing_context( nset, numstates, |
check_trailing_context (nset, numstates, |
accset, nacc ); |
accset, nacc); |
} |
|
} |
} |
|
} |
|
|
if ( ! fullspd ) |
if (!fullspd) { |
{ |
if (!snstods (nset, 0, accset, 0, 0, &end_of_buffer_state)) |
if ( ! snstods( nset, 0, accset, 0, 0, &end_of_buffer_state ) ) |
flexfatal (_ |
flexfatal( |
("could not create unique end-of-buffer state")); |
_( "could not create unique end-of-buffer state" ) ); |
|
|
|
++numas; |
++numas; |
++num_start_states; |
++num_start_states; |
++todo_next; |
++todo_next; |
} |
} |
|
|
while ( todo_head < todo_next ) |
|
{ |
while (todo_head < todo_next) { |
targptr = 0; |
targptr = 0; |
totaltrans = 0; |
totaltrans = 0; |
|
|
for ( i = 1; i <= numecs; ++i ) |
for (i = 1; i <= numecs; ++i) |
state[i] = 0; |
state[i] = 0; |
|
|
ds = ++todo_head; |
ds = ++todo_head; |
|
|
dset = dss[ds]; |
dset = dss[ds]; |
dsize = dfasiz[ds]; |
dsize = dfasiz[ds]; |
|
|
if ( trace ) |
if (trace) |
fprintf( stderr, _( "state # %d:\n" ), ds ); |
fprintf (stderr, _("state # %d:\n"), ds); |
|
|
sympartition( dset, dsize, symlist, duplist ); |
sympartition (dset, dsize, symlist, duplist); |
|
|
for ( sym = 1; sym <= numecs; ++sym ) |
for (sym = 1; sym <= numecs; ++sym) { |
{ |
if (symlist[sym]) { |
if ( symlist[sym] ) |
|
{ |
|
symlist[sym] = 0; |
symlist[sym] = 0; |
|
|
if ( duplist[sym] == NIL ) |
if (duplist[sym] == NIL) { |
{ |
|
/* Symbol has unique out-transitions. */ |
/* Symbol has unique out-transitions. */ |
numstates = symfollowset( dset, dsize, |
numstates = |
sym, nset ); |
symfollowset (dset, dsize, |
nset = epsclosure( nset, &numstates, |
sym, nset); |
accset, &nacc, &hashval ); |
nset = epsclosure (nset, |
|
&numstates, |
|
accset, &nacc, |
|
&hashval); |
|
|
if ( snstods( nset, numstates, accset, |
if (snstods |
nacc, hashval, &newds ) ) |
(nset, numstates, accset, nacc, |
{ |
hashval, &newds)) { |
totnst = totnst + numstates; |
totnst = totnst + |
|
numstates; |
++todo_next; |
++todo_next; |
numas += nacc; |
numas += nacc; |
|
|
if ( |
if (variable_trailing_context_rules && nacc > 0) |
variable_trailing_context_rules && |
check_trailing_context |
nacc > 0 ) |
(nset, |
check_trailing_context( |
numstates, |
nset, numstates, |
accset, |
accset, nacc ); |
nacc); |
} |
} |
|
|
state[sym] = newds; |
state[sym] = newds; |
|
|
if ( trace ) |
if (trace) |
fprintf( stderr, "\t%d\t%d\n", |
fprintf (stderr, |
sym, newds ); |
"\t%d\t%d\n", sym, |
|
newds); |
|
|
targfreq[++targptr] = 1; |
targfreq[++targptr] = 1; |
targstate[targptr] = newds; |
targstate[targptr] = newds; |
++numuniq; |
++numuniq; |
} |
} |
|
|
else |
else { |
{ |
|
/* sym's equivalence class has the same |
/* sym's equivalence class has the same |
* transitions as duplist(sym)'s |
* transitions as duplist(sym)'s |
* equivalence class. |
* equivalence class. |
|
|
targ = state[duplist[sym]]; |
targ = state[duplist[sym]]; |
state[sym] = targ; |
state[sym] = targ; |
|
|
if ( trace ) |
if (trace) |
fprintf( stderr, "\t%d\t%d\n", |
fprintf (stderr, |
sym, targ ); |
"\t%d\t%d\n", sym, |
|
targ); |
|
|
/* Update frequency count for |
/* Update frequency count for |
* destination state. |
* destination state. |
*/ |
*/ |
|
|
i = 0; |
i = 0; |
while ( targstate[++i] != targ ) |
while (targstate[++i] != targ) ; |
; |
|
|
|
++targfreq[i]; |
++targfreq[i]; |
++numdup; |
++numdup; |
} |
} |
|
|
++totaltrans; |
++totaltrans; |
duplist[sym] = NIL; |
duplist[sym] = NIL; |
} |
|
} |
} |
|
} |
|
|
if ( caseins && ! useecs ) |
|
{ |
|
int j; |
|
|
|
for ( i = 'A', j = 'a'; i <= 'Z'; ++i, ++j ) |
|
{ |
|
if ( state[i] == 0 && state[j] != 0 ) |
|
/* We're adding a transition. */ |
|
++totaltrans; |
|
|
|
else if ( state[i] != 0 && state[j] == 0 ) |
|
/* We're taking away a transition. */ |
|
--totaltrans; |
|
|
|
state[i] = state[j]; |
|
} |
|
} |
|
|
|
numsnpairs += totaltrans; |
numsnpairs += totaltrans; |
|
|
if ( ds > num_start_states ) |
if (ds > num_start_states) |
check_for_backing_up( ds, state ); |
check_for_backing_up (ds, state); |
|
|
if ( nultrans ) |
if (nultrans) { |
{ |
|
nultrans[ds] = state[NUL_ec]; |
nultrans[ds] = state[NUL_ec]; |
state[NUL_ec] = 0; /* remove transition */ |
state[NUL_ec] = 0; /* remove transition */ |
} |
} |
|
|
if ( fulltbl ) |
if (fulltbl) { |
{ |
|
outn( " {" ); |
|
|
|
|
/* Each time we hit here, it's another td_hilen, so we realloc. */ |
|
yynxt_tbl->td_hilen++; |
|
yynxt_tbl->td_data = yynxt_data = |
|
(flex_int32_t *) realloc (yynxt_data, |
|
yynxt_tbl->td_hilen * |
|
yynxt_tbl->td_lolen * |
|
sizeof (flex_int32_t)); |
|
|
|
|
|
if (gentables) |
|
outn (" {"); |
|
|
/* Supply array's 0-element. */ |
/* Supply array's 0-element. */ |
if ( ds == end_of_buffer_state ) |
if (ds == end_of_buffer_state) { |
mk2data( -end_of_buffer_state ); |
mk2data (-end_of_buffer_state); |
else |
yynxt_data[yynxt_curr++] = |
mk2data( end_of_buffer_state ); |
-end_of_buffer_state; |
|
} |
|
else { |
|
mk2data (end_of_buffer_state); |
|
yynxt_data[yynxt_curr++] = |
|
end_of_buffer_state; |
|
} |
|
|
for ( i = 1; i < num_full_table_rows; ++i ) |
for (i = 1; i < num_full_table_rows; ++i) { |
/* Jams are marked by negative of state |
/* Jams are marked by negative of state |
* number. |
* number. |
*/ |
*/ |
mk2data( state[i] ? state[i] : -ds ); |
mk2data (state[i] ? state[i] : -ds); |
|
yynxt_data[yynxt_curr++] = |
dataflush(); |
state[i] ? state[i] : -ds; |
outn( " },\n" ); |
|
} |
} |
|
|
else if ( fullspd ) |
dataflush (); |
place_state( state, ds, totaltrans ); |
if (gentables) |
|
outn (" },\n"); |
|
} |
|
|
else if ( ds == end_of_buffer_state ) |
else if (fullspd) |
|
place_state (state, ds, totaltrans); |
|
|
|
else if (ds == end_of_buffer_state) |
/* Special case this state to make sure it does what |
/* Special case this state to make sure it does what |
* it's supposed to, i.e., jam on end-of-buffer. |
* it's supposed to, i.e., jam on end-of-buffer. |
*/ |
*/ |
stack1( ds, 0, 0, JAMSTATE ); |
stack1 (ds, 0, 0, JAMSTATE); |
|
|
else /* normal, compressed state */ |
else { /* normal, compressed state */ |
{ |
|
/* Determine which destination state is the most |
/* Determine which destination state is the most |
* common, and how many transitions to it there are. |
* common, and how many transitions to it there are. |
*/ |
*/ |
|
|
comfreq = 0; |
comfreq = 0; |
comstate = 0; |
comstate = 0; |
|
|
for ( i = 1; i <= targptr; ++i ) |
for (i = 1; i <= targptr; ++i) |
if ( targfreq[i] > comfreq ) |
if (targfreq[i] > comfreq) { |
{ |
|
comfreq = targfreq[i]; |
comfreq = targfreq[i]; |
comstate = targstate[i]; |
comstate = targstate[i]; |
} |
} |
|
|
bldtbl( state, ds, totaltrans, comstate, comfreq ); |
bldtbl (state, ds, totaltrans, comstate, comfreq); |
} |
|
} |
} |
|
} |
|
|
if ( fulltbl ) |
if (fulltbl) { |
dataend(); |
dataend (); |
|
if (tablesext) { |
|
yytbl_data_compress (yynxt_tbl); |
|
if (yytbl_data_fwrite (&tableswr, yynxt_tbl) < 0) |
|
flexerror (_ |
|
("Could not write yynxt_tbl[][]")); |
|
} |
|
if (yynxt_tbl) { |
|
yytbl_data_destroy (yynxt_tbl); |
|
yynxt_tbl = 0; |
|
} |
|
} |
|
|
else if ( ! fullspd ) |
else if (!fullspd) { |
{ |
cmptmps (); /* create compressed template entries */ |
cmptmps(); /* create compressed template entries */ |
|
|
|
/* Create tables for all the states with only one |
/* Create tables for all the states with only one |
* out-transition. |
* out-transition. |
*/ |
*/ |
while ( onesp > 0 ) |
while (onesp > 0) { |
{ |
mk1tbl (onestate[onesp], onesym[onesp], |
mk1tbl( onestate[onesp], onesym[onesp], onenext[onesp], |
onenext[onesp], onedef[onesp]); |
onedef[onesp] ); |
|
--onesp; |
--onesp; |
} |
|
|
|
mkdeftbl(); |
|
} |
} |
|
|
flex_free( (void *) accset ); |
mkdeftbl (); |
flex_free( (void *) nset ); |
|
} |
} |
|
|
|
flex_free ((void *) accset); |
|
flex_free ((void *) nset); |
|
} |
|
|
|
|
/* snstods - converts a set of ndfa states into a dfa state |
/* snstods - converts a set of ndfa states into a dfa state |
* |
* |
* synopsis |
* synopsis |
|
|
* On return, the dfa state number is in newds. |
* On return, the dfa state number is in newds. |
*/ |
*/ |
|
|
int snstods( sns, numstates, accset, nacc, hashval, newds_addr ) |
int snstods (sns, numstates, accset, nacc, hashval, newds_addr) |
int sns[], numstates, accset[], nacc, hashval, *newds_addr; |
int sns[], numstates, accset[], nacc, hashval, *newds_addr; |
{ |
{ |
int didsort = 0; |
int didsort = 0; |
int i, j; |
int i, j; |
int newds, *oldsns; |
int newds, *oldsns; |
|
|
for ( i = 1; i <= lastdfa; ++i ) |
for (i = 1; i <= lastdfa; ++i) |
if ( hashval == dhash[i] ) |
if (hashval == dhash[i]) { |
{ |
if (numstates == dfasiz[i]) { |
if ( numstates == dfasiz[i] ) |
|
{ |
|
oldsns = dss[i]; |
oldsns = dss[i]; |
|
|
if ( ! didsort ) |
if (!didsort) { |
{ |
|
/* We sort the states in sns so we |
/* We sort the states in sns so we |
* can compare it to oldsns quickly. |
* can compare it to oldsns quickly. |
* We use bubble because there probably |
|
* aren't very many states. |
|
*/ |
*/ |
bubble( sns, numstates ); |
qsort (&sns [1], numstates, sizeof (sns [1]), intcmp); |
didsort = 1; |
didsort = 1; |
} |
} |
|
|
for ( j = 1; j <= numstates; ++j ) |
for (j = 1; j <= numstates; ++j) |
if ( sns[j] != oldsns[j] ) |
if (sns[j] != oldsns[j]) |
break; |
break; |
|
|
if ( j > numstates ) |
if (j > numstates) { |
{ |
|
++dfaeql; |
++dfaeql; |
*newds_addr = i; |
*newds_addr = i; |
return 0; |
return 0; |
} |
} |
|
|
++hshcol; |
++hshcol; |
} |
} |
|
|
else |
else |
++hshsave; |
++hshsave; |
} |
} |
|
|
/* Make a new dfa. */ |
/* Make a new dfa. */ |
|
|
if ( ++lastdfa >= current_max_dfas ) |
if (++lastdfa >= current_max_dfas) |
increase_max_dfas(); |
increase_max_dfas (); |
|
|
newds = lastdfa; |
newds = lastdfa; |
|
|
dss[newds] = allocate_integer_array( numstates + 1 ); |
dss[newds] = allocate_integer_array (numstates + 1); |
|
|
/* If we haven't already sorted the states in sns, we do so now, |
/* If we haven't already sorted the states in sns, we do so now, |
* so that future comparisons with it can be made quickly. |
* so that future comparisons with it can be made quickly. |
*/ |
*/ |
|
|
if ( ! didsort ) |
if (!didsort) |
bubble( sns, numstates ); |
qsort (&sns [1], numstates, sizeof (sns [1]), intcmp); |
|
|
for ( i = 1; i <= numstates; ++i ) |
for (i = 1; i <= numstates; ++i) |
dss[newds][i] = sns[i]; |
dss[newds][i] = sns[i]; |
|
|
dfasiz[newds] = numstates; |
dfasiz[newds] = numstates; |
dhash[newds] = hashval; |
dhash[newds] = hashval; |
|
|
if ( nacc == 0 ) |
if (nacc == 0) { |
{ |
if (reject) |
if ( reject ) |
|
dfaacc[newds].dfaacc_set = (int *) 0; |
dfaacc[newds].dfaacc_set = (int *) 0; |
else |
else |
dfaacc[newds].dfaacc_state = 0; |
dfaacc[newds].dfaacc_state = 0; |
|
|
accsiz[newds] = 0; |
accsiz[newds] = 0; |
} |
} |
|
|
else if ( reject ) |
else if (reject) { |
{ |
|
/* We sort the accepting set in increasing order so the |
/* We sort the accepting set in increasing order so the |
* disambiguating rule that the first rule listed is considered |
* disambiguating rule that the first rule listed is considered |
* match in the event of ties will work. We use a bubble |
* match in the event of ties will work. |
* sort since the list is probably quite small. |
|
*/ |
*/ |
|
|
bubble( accset, nacc ); |
qsort (&accset [1], nacc, sizeof (accset [1]), intcmp); |
|
|
dfaacc[newds].dfaacc_set = allocate_integer_array( nacc + 1 ); |
dfaacc[newds].dfaacc_set = |
|
allocate_integer_array (nacc + 1); |
|
|
/* Save the accepting set for later */ |
/* Save the accepting set for later */ |
for ( i = 1; i <= nacc; ++i ) |
for (i = 1; i <= nacc; ++i) { |
{ |
|
dfaacc[newds].dfaacc_set[i] = accset[i]; |
dfaacc[newds].dfaacc_set[i] = accset[i]; |
|
|
if ( accset[i] <= num_rules ) |
if (accset[i] <= num_rules) |
/* Who knows, perhaps a REJECT can yield |
/* Who knows, perhaps a REJECT can yield |
* this rule. |
* this rule. |
*/ |
*/ |
rule_useful[accset[i]] = true; |
rule_useful[accset[i]] = true; |
} |
} |
|
|
accsiz[newds] = nacc; |
accsiz[newds] = nacc; |
} |
} |
|
|
else |
else { |
{ |
|
/* Find lowest numbered rule so the disambiguating rule |
/* Find lowest numbered rule so the disambiguating rule |
* will work. |
* will work. |
*/ |
*/ |
j = num_rules + 1; |
j = num_rules + 1; |
|
|
for ( i = 1; i <= nacc; ++i ) |
for (i = 1; i <= nacc; ++i) |
if ( accset[i] < j ) |
if (accset[i] < j) |
j = accset[i]; |
j = accset[i]; |
|
|
dfaacc[newds].dfaacc_state = j; |
dfaacc[newds].dfaacc_state = j; |
|
|
if ( j <= num_rules ) |
if (j <= num_rules) |
rule_useful[j] = true; |
rule_useful[j] = true; |
} |
} |
|
|
*newds_addr = newds; |
*newds_addr = newds; |
|
|
return 1; |
return 1; |
} |
} |
|
|
|
|
/* symfollowset - follow the symbol transitions one step |
/* symfollowset - follow the symbol transitions one step |
|
|
* int transsym, int nset[current_max_dfa_size] ); |
* int transsym, int nset[current_max_dfa_size] ); |
*/ |
*/ |
|
|
int symfollowset( ds, dsize, transsym, nset ) |
int symfollowset (ds, dsize, transsym, nset) |
int ds[], dsize, transsym, nset[]; |
int ds[], dsize, transsym, nset[]; |
{ |
{ |
int ns, tsp, sym, i, j, lenccl, ch, numstates, ccllist; |
int ns, tsp, sym, i, j, lenccl, ch, numstates, ccllist; |
|
|
numstates = 0; |
numstates = 0; |
|
|
for ( i = 1; i <= dsize; ++i ) |
for (i = 1; i <= dsize; ++i) { /* for each nfa state ns in the state set of ds */ |
{ /* for each nfa state ns in the state set of ds */ |
|
ns = ds[i]; |
ns = ds[i]; |
sym = transchar[ns]; |
sym = transchar[ns]; |
tsp = trans1[ns]; |
tsp = trans1[ns]; |
|
|
if ( sym < 0 ) |
if (sym < 0) { /* it's a character class */ |
{ /* it's a character class */ |
|
sym = -sym; |
sym = -sym; |
ccllist = cclmap[sym]; |
ccllist = cclmap[sym]; |
lenccl = ccllen[sym]; |
lenccl = ccllen[sym]; |
|
|
if ( cclng[sym] ) |
if (cclng[sym]) { |
{ |
for (j = 0; j < lenccl; ++j) { |
for ( j = 0; j < lenccl; ++j ) |
|
{ |
|
/* Loop through negated character |
/* Loop through negated character |
* class. |
* class. |
*/ |
*/ |
ch = ccltbl[ccllist + j]; |
ch = ccltbl[ccllist + j]; |
|
|
if ( ch == 0 ) |
if (ch == 0) |
ch = NUL_ec; |
ch = NUL_ec; |
|
|
if ( ch > transsym ) |
if (ch > transsym) |
/* Transsym isn't in negated |
/* Transsym isn't in negated |
* ccl. |
* ccl. |
*/ |
*/ |
break; |
break; |
|
|
else if ( ch == transsym ) |
else if (ch == transsym) |
/* next 2 */ goto bottom; |
/* next 2 */ |
} |
goto bottom; |
|
} |
|
|
/* Didn't find transsym in ccl. */ |
/* Didn't find transsym in ccl. */ |
nset[++numstates] = tsp; |
nset[++numstates] = tsp; |
} |
} |
|
|
else |
else |
for ( j = 0; j < lenccl; ++j ) |
for (j = 0; j < lenccl; ++j) { |
{ |
|
ch = ccltbl[ccllist + j]; |
ch = ccltbl[ccllist + j]; |
|
|
if ( ch == 0 ) |
if (ch == 0) |
ch = NUL_ec; |
ch = NUL_ec; |
|
|
if ( ch > transsym ) |
if (ch > transsym) |
break; |
break; |
else if ( ch == transsym ) |
else if (ch == transsym) { |
{ |
|
nset[++numstates] = tsp; |
nset[++numstates] = tsp; |
break; |
break; |
} |
|
} |
} |
} |
} |
|
} |
|
|
else if ( sym >= 'A' && sym <= 'Z' && caseins ) |
else if (sym == SYM_EPSILON) { /* do nothing */ |
flexfatal( |
} |
_( "consistency check failed in symfollowset" ) ); |
|
|
|
else if ( sym == SYM_EPSILON ) |
else if (ABS (ecgroup[sym]) == transsym) |
{ /* do nothing */ |
|
} |
|
|
|
else if ( ABS( ecgroup[sym] ) == transsym ) |
|
nset[++numstates] = tsp; |
nset[++numstates] = tsp; |
|
|
bottom: ; |
bottom:; |
} |
} |
|
|
return numstates; |
return numstates; |
} |
} |
|
|
|
|
/* sympartition - partition characters with same out-transitions |
/* sympartition - partition characters with same out-transitions |
|
|
* int symlist[numecs], int duplist[numecs] ); |
* int symlist[numecs], int duplist[numecs] ); |
*/ |
*/ |
|
|
void sympartition( ds, numstates, symlist, duplist ) |
void sympartition (ds, numstates, symlist, duplist) |
int ds[], numstates; |
int ds[], numstates; |
int symlist[], duplist[]; |
int symlist[], duplist[]; |
{ |
{ |
int tch, i, j, k, ns, dupfwd[CSIZE + 1], lenccl, cclp, ich; |
int tch, i, j, k, ns, dupfwd[CSIZE + 1], lenccl, cclp, ich; |
|
|
/* Partitioning is done by creating equivalence classes for those |
/* Partitioning is done by creating equivalence classes for those |
* characters which have out-transitions from the given state. Thus |
* characters which have out-transitions from the given state. Thus |
* we are really creating equivalence classes of equivalence classes. |
* we are really creating equivalence classes of equivalence classes. |
*/ |
*/ |
|
|
for ( i = 1; i <= numecs; ++i ) |
for (i = 1; i <= numecs; ++i) { /* initialize equivalence class list */ |
{ /* initialize equivalence class list */ |
|
duplist[i] = i - 1; |
duplist[i] = i - 1; |
dupfwd[i] = i + 1; |
dupfwd[i] = i + 1; |
} |
} |
|
|
duplist[1] = NIL; |
duplist[1] = NIL; |
dupfwd[numecs] = NIL; |
dupfwd[numecs] = NIL; |
|
|
for ( i = 1; i <= numstates; ++i ) |
for (i = 1; i <= numstates; ++i) { |
{ |
|
ns = ds[i]; |
ns = ds[i]; |
tch = transchar[ns]; |
tch = transchar[ns]; |
|
|
if ( tch != SYM_EPSILON ) |
if (tch != SYM_EPSILON) { |
{ |
if (tch < -lastccl || tch >= csize) { |
if ( tch < -lastccl || tch >= csize ) |
flexfatal (_ |
{ |
("bad transition character detected in sympartition()")); |
flexfatal( |
} |
_( "bad transition character detected in sympartition()" ) ); |
|
} |
|
|
|
if ( tch >= 0 ) |
if (tch >= 0) { /* character transition */ |
{ /* character transition */ |
int ec = ecgroup[tch]; |
int ec = ecgroup[tch]; |
|
|
|
mkechar( ec, dupfwd, duplist ); |
mkechar (ec, dupfwd, duplist); |
symlist[ec] = 1; |
symlist[ec] = 1; |
} |
} |
|
|
else |
else { /* character class */ |
{ /* character class */ |
|
tch = -tch; |
tch = -tch; |
|
|
lenccl = ccllen[tch]; |
lenccl = ccllen[tch]; |
cclp = cclmap[tch]; |
cclp = cclmap[tch]; |
mkeccl( ccltbl + cclp, lenccl, dupfwd, |
mkeccl (ccltbl + cclp, lenccl, dupfwd, |
duplist, numecs, NUL_ec ); |
duplist, numecs, NUL_ec); |
|
|
if ( cclng[tch] ) |
if (cclng[tch]) { |
{ |
|
j = 0; |
j = 0; |
|
|
for ( k = 0; k < lenccl; ++k ) |
for (k = 0; k < lenccl; ++k) { |
{ |
|
ich = ccltbl[cclp + k]; |
ich = ccltbl[cclp + k]; |
|
|
if ( ich == 0 ) |
if (ich == 0) |
ich = NUL_ec; |
ich = NUL_ec; |
|
|
for ( ++j; j < ich; ++j ) |
for (++j; j < ich; ++j) |
symlist[j] = 1; |
symlist[j] = 1; |
} |
} |
|
|
for ( ++j; j <= numecs; ++j ) |
for (++j; j <= numecs; ++j) |
symlist[j] = 1; |
symlist[j] = 1; |
} |
} |
|
|
else |
else |
for ( k = 0; k < lenccl; ++k ) |
for (k = 0; k < lenccl; ++k) { |
{ |
|
ich = ccltbl[cclp + k]; |
ich = ccltbl[cclp + k]; |
|
|
if ( ich == 0 ) |
if (ich == 0) |
ich = NUL_ec; |
ich = NUL_ec; |
|
|
symlist[ich] = 1; |
symlist[ich] = 1; |
} |
} |
} |
|
} |
} |
} |
} |
} |
} |
|
} |