version 1.9, 2003/06/04 17:34:44 |
version 1.10, 2015/11/19 19:43:40 |
|
|
|
|
/* nfa - NFA construction routines */ |
/* nfa - NFA 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. */ |
|
|
|
/* 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. */ |
|
|
|
/* This file is part of flex. */ |
|
|
|
/* 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 "flexdef.h" |
|
|
|
|
/* declare functions that have forward references */ |
/* declare functions that have forward references */ |
|
|
int dupmachine PROTO((int)); |
int dupmachine PROTO ((int)); |
void mkxtion PROTO((int, int)); |
void mkxtion PROTO ((int, int)); |
|
|
|
|
/* add_accept - add an accepting state to a machine |
/* add_accept - add an accepting state to a machine |
|
|
* accepting_number becomes mach's accepting number. |
* accepting_number becomes mach's accepting number. |
*/ |
*/ |
|
|
void add_accept( mach, accepting_number ) |
void add_accept (mach, accepting_number) |
int mach, accepting_number; |
int mach, accepting_number; |
{ |
{ |
/* Hang the accepting number off an epsilon state. if it is associated |
/* Hang the accepting number off an epsilon state. if it is associated |
* with a state that has a non-epsilon out-transition, then the state |
* with a state that has a non-epsilon out-transition, then the state |
* will accept BEFORE it makes that transition, i.e., one character |
* will accept BEFORE it makes that transition, i.e., one character |
* too soon. |
* too soon. |
*/ |
*/ |
|
|
if ( transchar[finalst[mach]] == SYM_EPSILON ) |
if (transchar[finalst[mach]] == SYM_EPSILON) |
accptnum[finalst[mach]] = accepting_number; |
accptnum[finalst[mach]] = accepting_number; |
|
|
else |
else { |
{ |
int astate = mkstate (SYM_EPSILON); |
int astate = mkstate( SYM_EPSILON ); |
|
accptnum[astate] = accepting_number; |
accptnum[astate] = accepting_number; |
(void) link_machines( mach, astate ); |
(void) link_machines (mach, astate); |
} |
|
} |
} |
|
} |
|
|
|
|
/* copysingl - make a given number of copies of a singleton machine |
/* copysingl - make a given number of copies of a singleton machine |
|
|
* num - the number of copies of singl to be present in newsng |
* num - the number of copies of singl to be present in newsng |
*/ |
*/ |
|
|
int copysingl( singl, num ) |
int copysingl (singl, num) |
int singl, num; |
int singl, num; |
{ |
{ |
int copy, i; |
int copy, i; |
|
|
copy = mkstate( SYM_EPSILON ); |
copy = mkstate (SYM_EPSILON); |
|
|
for ( i = 1; i <= num; ++i ) |
for (i = 1; i <= num; ++i) |
copy = link_machines( copy, dupmachine( singl ) ); |
copy = link_machines (copy, dupmachine (singl)); |
|
|
return copy; |
return copy; |
} |
} |
|
|
|
|
/* dumpnfa - debugging routine to write out an nfa */ |
/* dumpnfa - debugging routine to write out an nfa */ |
|
|
void dumpnfa( state1 ) |
void dumpnfa (state1) |
int state1; |
int state1; |
|
|
{ |
{ |
int sym, tsp1, tsp2, anum, ns; |
int sym, tsp1, tsp2, anum, ns; |
|
|
fprintf( stderr, |
fprintf (stderr, |
_( "\n\n********** beginning dump of nfa with start state %d\n" ), |
_ |
state1 ); |
("\n\n********** beginning dump of nfa with start state %d\n"), |
|
state1); |
|
|
/* We probably should loop starting at firstst[state1] and going to |
/* We probably should loop starting at firstst[state1] and going to |
* lastst[state1], but they're not maintained properly when we "or" |
* lastst[state1], but they're not maintained properly when we "or" |
|
|
*/ |
*/ |
|
|
/* for ( ns = firstst[state1]; ns <= lastst[state1]; ++ns ) */ |
/* for ( ns = firstst[state1]; ns <= lastst[state1]; ++ns ) */ |
for ( ns = 1; ns <= lastnfa; ++ns ) |
for (ns = 1; ns <= lastnfa; ++ns) { |
{ |
fprintf (stderr, _("state # %4d\t"), ns); |
fprintf( stderr, _( "state # %4d\t" ), ns ); |
|
|
|
sym = transchar[ns]; |
sym = transchar[ns]; |
tsp1 = trans1[ns]; |
tsp1 = trans1[ns]; |
tsp2 = trans2[ns]; |
tsp2 = trans2[ns]; |
anum = accptnum[ns]; |
anum = accptnum[ns]; |
|
|
fprintf( stderr, "%3d: %4d, %4d", sym, tsp1, tsp2 ); |
fprintf (stderr, "%3d: %4d, %4d", sym, tsp1, tsp2); |
|
|
if ( anum != NIL ) |
if (anum != NIL) |
fprintf( stderr, " [%d]", anum ); |
fprintf (stderr, " [%d]", anum); |
|
|
fprintf( stderr, "\n" ); |
fprintf (stderr, "\n"); |
} |
|
|
|
fprintf( stderr, _( "********** end of dump\n" ) ); |
|
} |
} |
|
|
|
fprintf (stderr, _("********** end of dump\n")); |
|
} |
|
|
|
|
/* dupmachine - make a duplicate of a given machine |
/* dupmachine - make a duplicate of a given machine |
* |
* |
* synopsis |
* synopsis |
|
|
* states accessible by the arrays firstst and lastst |
* states accessible by the arrays firstst and lastst |
*/ |
*/ |
|
|
int dupmachine( mach ) |
int dupmachine (mach) |
int mach; |
int mach; |
{ |
{ |
int i, init, state_offset; |
int i, init, state_offset; |
int state = 0; |
int state = 0; |
int last = lastst[mach]; |
int last = lastst[mach]; |
|
|
for ( i = firstst[mach]; i <= last; ++i ) |
for (i = firstst[mach]; i <= last; ++i) { |
{ |
state = mkstate (transchar[i]); |
state = mkstate( transchar[i] ); |
|
|
|
if ( trans1[i] != NO_TRANSITION ) |
if (trans1[i] != NO_TRANSITION) { |
{ |
mkxtion (finalst[state], trans1[i] + state - i); |
mkxtion( finalst[state], trans1[i] + state - i ); |
|
|
|
if ( transchar[i] == SYM_EPSILON && |
if (transchar[i] == SYM_EPSILON && |
trans2[i] != NO_TRANSITION ) |
trans2[i] != NO_TRANSITION) |
mkxtion( finalst[state], |
mkxtion (finalst[state], |
trans2[i] + state - i ); |
trans2[i] + state - i); |
} |
} |
|
|
accptnum[state] = accptnum[i]; |
accptnum[state] = accptnum[i]; |
} |
} |
|
|
if ( state == 0 ) |
if (state == 0) |
flexfatal( _( "empty machine in dupmachine()" ) ); |
flexfatal (_("empty machine in dupmachine()")); |
|
|
state_offset = state - i + 1; |
state_offset = state - i + 1; |
|
|
|
|
lastst[init] = lastst[mach] + state_offset; |
lastst[init] = lastst[mach] + state_offset; |
|
|
return init; |
return init; |
} |
} |
|
|
|
|
/* finish_rule - finish up the processing for a rule |
/* finish_rule - finish up the processing for a rule |
|
|
* context has variable length. |
* context has variable length. |
*/ |
*/ |
|
|
void finish_rule( mach, variable_trail_rule, headcnt, trailcnt ) |
void finish_rule (mach, variable_trail_rule, headcnt, trailcnt, |
int mach, variable_trail_rule, headcnt, trailcnt; |
pcont_act) |
{ |
int mach, variable_trail_rule, headcnt, trailcnt, pcont_act; |
char action_text[MAXLINE]; |
{ |
|
char action_text[MAXLINE]; |
|
|
add_accept( mach, num_rules ); |
add_accept (mach, num_rules); |
|
|
/* We did this in new_rule(), but it often gets the wrong |
/* We did this in new_rule(), but it often gets the wrong |
* number because we do it before we start parsing the current rule. |
* number because we do it before we start parsing the current rule. |
|
|
/* If this is a continued action, then the line-number has already |
/* If this is a continued action, then the line-number has already |
* been updated, giving us the wrong number. |
* been updated, giving us the wrong number. |
*/ |
*/ |
if ( continued_action ) |
if (continued_action) |
--rule_linenum[num_rules]; |
--rule_linenum[num_rules]; |
|
|
snprintf( action_text, sizeof action_text, "case %d:\n", num_rules ); |
|
add_action( action_text ); |
|
|
|
if ( variable_trail_rule ) |
/* If the previous rule was continued action, then we inherit the |
{ |
* previous newline flag, possibly overriding the current one. |
|
*/ |
|
if (pcont_act && rule_has_nl[num_rules - 1]) |
|
rule_has_nl[num_rules] = true; |
|
|
|
snprintf (action_text, sizeof(action_text), "case %d:\n", num_rules); |
|
add_action (action_text); |
|
if (rule_has_nl[num_rules]) { |
|
snprintf (action_text, sizeof(action_text), "/* rule %d can match eol */\n", |
|
num_rules); |
|
add_action (action_text); |
|
} |
|
|
|
|
|
if (variable_trail_rule) { |
rule_type[num_rules] = RULE_VARIABLE; |
rule_type[num_rules] = RULE_VARIABLE; |
|
|
if ( performance_report > 0 ) |
if (performance_report > 0) |
fprintf( stderr, |
fprintf (stderr, |
_( "Variable trailing context rule at line %d\n" ), |
_ |
rule_linenum[num_rules] ); |
("Variable trailing context rule at line %d\n"), |
|
rule_linenum[num_rules]); |
|
|
variable_trailing_context_rules = true; |
variable_trailing_context_rules = true; |
} |
} |
|
|
else |
else { |
{ |
|
rule_type[num_rules] = RULE_NORMAL; |
rule_type[num_rules] = RULE_NORMAL; |
|
|
if ( headcnt > 0 || trailcnt > 0 ) |
if (headcnt > 0 || trailcnt > 0) { |
{ |
|
/* Do trailing context magic to not match the trailing |
/* Do trailing context magic to not match the trailing |
* characters. |
* characters. |
*/ |
*/ |
char *scanner_cp = "yy_c_buf_p = yy_cp"; |
char *scanner_cp = "YY_G(yy_c_buf_p) = yy_cp"; |
char *scanner_bp = "yy_bp"; |
char *scanner_bp = "yy_bp"; |
|
|
add_action( |
add_action |
"*yy_cp = yy_hold_char; /* undo effects of setting up yytext */\n" ); |
("*yy_cp = YY_G(yy_hold_char); /* undo effects of setting up yytext */\n"); |
|
|
if ( headcnt > 0 ) |
if (headcnt > 0) { |
{ |
if (rule_has_nl[num_rules]) { |
snprintf( action_text, sizeof action_text, |
snprintf (action_text, sizeof(action_text), |
"%s = %s + %d;\n", |
"YY_LINENO_REWIND_TO(%s + %d);\n", scanner_bp, headcnt); |
scanner_cp, scanner_bp, headcnt ); |
add_action (action_text); |
add_action( action_text ); |
|
} |
} |
|
snprintf (action_text, sizeof(action_text), "%s = %s + %d;\n", |
|
scanner_cp, scanner_bp, headcnt); |
|
add_action (action_text); |
|
} |
|
|
else |
else { |
{ |
if (rule_has_nl[num_rules]) { |
snprintf( action_text, sizeof action_text, |
snprintf (action_text, sizeof(action_text), |
"%s -= %d;\n", |
"YY_LINENO_REWIND_TO(yy_cp - %d);\n", trailcnt); |
scanner_cp, trailcnt ); |
add_action (action_text); |
add_action( action_text ); |
|
} |
} |
|
|
add_action( |
snprintf (action_text, sizeof(action_text), "%s -= %d;\n", |
"YY_DO_BEFORE_ACTION; /* set up yytext again */\n" ); |
scanner_cp, trailcnt); |
|
add_action (action_text); |
} |
} |
|
|
|
add_action |
|
("YY_DO_BEFORE_ACTION; /* set up yytext again */\n"); |
} |
} |
|
} |
|
|
/* Okay, in the action code at this point yytext and yyleng have |
/* Okay, in the action code at this point yytext and yyleng have |
* their proper final values for this rule, so here's the point |
* their proper final values for this rule, so here's the point |
* to do any user action. But don't do it for continued actions, |
* to do any user action. But don't do it for continued actions, |
* as that'll result in multiple YY_RULE_SETUP's. |
* as that'll result in multiple YY_RULE_SETUP's. |
*/ |
*/ |
if ( ! continued_action ) |
if (!continued_action) |
add_action( "YY_RULE_SETUP\n" ); |
add_action ("YY_RULE_SETUP\n"); |
|
|
line_directive_out( (FILE *) 0, 1 ); |
line_directive_out ((FILE *) 0, 1); |
} |
} |
|
|
|
|
/* link_machines - connect two machines together |
/* link_machines - connect two machines together |
|
|
* FIRST is set to new by the operation. last is unmolested. |
* FIRST is set to new by the operation. last is unmolested. |
*/ |
*/ |
|
|
int link_machines( first, last ) |
int link_machines (first, last) |
int first, last; |
int first, last; |
{ |
{ |
if ( first == NIL ) |
if (first == NIL) |
return last; |
return last; |
|
|
else if ( last == NIL ) |
else if (last == NIL) |
return first; |
return first; |
|
|
else |
else { |
{ |
mkxtion (finalst[first], last); |
mkxtion( finalst[first], last ); |
|
finalst[first] = finalst[last]; |
finalst[first] = finalst[last]; |
lastst[first] = MAX( lastst[first], lastst[last] ); |
lastst[first] = MAX (lastst[first], lastst[last]); |
firstst[first] = MIN( firstst[first], firstst[last] ); |
firstst[first] = MIN (firstst[first], firstst[last]); |
|
|
return first; |
return first; |
} |
|
} |
} |
|
} |
|
|
|
|
/* mark_beginning_as_normal - mark each "beginning" state in a machine |
/* mark_beginning_as_normal - mark each "beginning" state in a machine |
|
|
* The "beginning" states are the epsilon closure of the first state |
* The "beginning" states are the epsilon closure of the first state |
*/ |
*/ |
|
|
void mark_beginning_as_normal( mach ) |
void mark_beginning_as_normal (mach) |
int mach; |
int mach; |
{ |
{ |
switch ( state_type[mach] ) |
switch (state_type[mach]) { |
{ |
case STATE_NORMAL: |
case STATE_NORMAL: |
/* Oh, we've already visited here. */ |
/* Oh, we've already visited here. */ |
return; |
return; |
|
|
|
case STATE_TRAILING_CONTEXT: |
case STATE_TRAILING_CONTEXT: |
state_type[mach] = STATE_NORMAL; |
state_type[mach] = STATE_NORMAL; |
|
|
if ( transchar[mach] == SYM_EPSILON ) |
if (transchar[mach] == SYM_EPSILON) { |
{ |
if (trans1[mach] != NO_TRANSITION) |
if ( trans1[mach] != NO_TRANSITION ) |
mark_beginning_as_normal (trans1[mach]); |
mark_beginning_as_normal( |
|
trans1[mach] ); |
|
|
|
if ( trans2[mach] != NO_TRANSITION ) |
if (trans2[mach] != NO_TRANSITION) |
mark_beginning_as_normal( |
mark_beginning_as_normal (trans2[mach]); |
trans2[mach] ); |
|
} |
|
break; |
|
|
|
default: |
|
flexerror( |
|
_( "bad state type in mark_beginning_as_normal()" ) ); |
|
break; |
|
} |
} |
|
break; |
|
|
|
default: |
|
flexerror (_ |
|
("bad state type in mark_beginning_as_normal()")); |
|
break; |
} |
} |
|
} |
|
|
|
|
/* mkbranch - make a machine that branches to two machines |
/* mkbranch - make a machine that branches to two machines |
|
|
* more mkbranch's. Compare with mkor() |
* more mkbranch's. Compare with mkor() |
*/ |
*/ |
|
|
int mkbranch( first, second ) |
int mkbranch (first, second) |
int first, second; |
int first, second; |
{ |
{ |
int eps; |
int eps; |
|
|
if ( first == NO_TRANSITION ) |
if (first == NO_TRANSITION) |
return second; |
return second; |
|
|
else if ( second == NO_TRANSITION ) |
else if (second == NO_TRANSITION) |
return first; |
return first; |
|
|
eps = mkstate( SYM_EPSILON ); |
eps = mkstate (SYM_EPSILON); |
|
|
mkxtion( eps, first ); |
mkxtion (eps, first); |
mkxtion( eps, second ); |
mkxtion (eps, second); |
|
|
return eps; |
return eps; |
} |
} |
|
|
|
|
/* mkclos - convert a machine into a closure |
/* mkclos - convert a machine into a closure |
|
|
* new - a new state which matches the closure of "state" |
* new - a new state which matches the closure of "state" |
*/ |
*/ |
|
|
int mkclos( state ) |
int mkclos (state) |
int state; |
int state; |
{ |
{ |
return mkopt( mkposcl( state ) ); |
return mkopt (mkposcl (state)); |
} |
} |
|
|
|
|
/* mkopt - make a machine optional |
/* mkopt - make a machine optional |
|
|
* 2. mach is destroyed by the call |
* 2. mach is destroyed by the call |
*/ |
*/ |
|
|
int mkopt( mach ) |
int mkopt (mach) |
int mach; |
int mach; |
{ |
{ |
int eps; |
int eps; |
|
|
if ( ! SUPER_FREE_EPSILON(finalst[mach]) ) |
if (!SUPER_FREE_EPSILON (finalst[mach])) { |
{ |
eps = mkstate (SYM_EPSILON); |
eps = mkstate( SYM_EPSILON ); |
mach = link_machines (mach, eps); |
mach = link_machines( mach, eps ); |
} |
} |
|
|
|
/* Can't skimp on the following if FREE_EPSILON(mach) is true because |
/* Can't skimp on the following if FREE_EPSILON(mach) is true because |
* some state interior to "mach" might point back to the beginning |
* some state interior to "mach" might point back to the beginning |
* for a closure. |
* for a closure. |
*/ |
*/ |
eps = mkstate( SYM_EPSILON ); |
eps = mkstate (SYM_EPSILON); |
mach = link_machines( eps, mach ); |
mach = link_machines (eps, mach); |
|
|
mkxtion( mach, finalst[mach] ); |
mkxtion (mach, finalst[mach]); |
|
|
return mach; |
return mach; |
} |
} |
|
|
|
|
/* mkor - make a machine that matches either one of two machines |
/* mkor - make a machine that matches either one of two machines |
|
|
* the number of epsilon states needed |
* the number of epsilon states needed |
*/ |
*/ |
|
|
int mkor( first, second ) |
int mkor (first, second) |
int first, second; |
int first, second; |
{ |
{ |
int eps, orend; |
int eps, orend; |
|
|
if ( first == NIL ) |
if (first == NIL) |
return second; |
return second; |
|
|
else if ( second == NIL ) |
else if (second == NIL) |
return first; |
return first; |
|
|
else |
else { |
{ |
|
/* See comment in mkopt() about why we can't use the first |
/* See comment in mkopt() about why we can't use the first |
* state of "first" or "second" if they satisfy "FREE_EPSILON". |
* state of "first" or "second" if they satisfy "FREE_EPSILON". |
*/ |
*/ |
eps = mkstate( SYM_EPSILON ); |
eps = mkstate (SYM_EPSILON); |
|
|
first = link_machines( eps, first ); |
first = link_machines (eps, first); |
|
|
mkxtion( first, second ); |
mkxtion (first, second); |
|
|
if ( SUPER_FREE_EPSILON(finalst[first]) && |
if (SUPER_FREE_EPSILON (finalst[first]) && |
accptnum[finalst[first]] == NIL ) |
accptnum[finalst[first]] == NIL) { |
{ |
|
orend = finalst[first]; |
orend = finalst[first]; |
mkxtion( finalst[second], orend ); |
mkxtion (finalst[second], orend); |
} |
} |
|
|
else if ( SUPER_FREE_EPSILON(finalst[second]) && |
else if (SUPER_FREE_EPSILON (finalst[second]) && |
accptnum[finalst[second]] == NIL ) |
accptnum[finalst[second]] == NIL) { |
{ |
|
orend = finalst[second]; |
orend = finalst[second]; |
mkxtion( finalst[first], orend ); |
mkxtion (finalst[first], orend); |
} |
} |
|
|
else |
else { |
{ |
eps = mkstate (SYM_EPSILON); |
eps = mkstate( SYM_EPSILON ); |
|
|
|
first = link_machines( first, eps ); |
first = link_machines (first, eps); |
orend = finalst[first]; |
orend = finalst[first]; |
|
|
mkxtion( finalst[second], orend ); |
mkxtion (finalst[second], orend); |
} |
|
} |
} |
|
} |
|
|
finalst[first] = orend; |
finalst[first] = orend; |
return first; |
return first; |
} |
} |
|
|
|
|
/* mkposcl - convert a machine into a positive closure |
/* mkposcl - convert a machine into a positive closure |
|
|
* new - a machine matching the positive closure of "state" |
* new - a machine matching the positive closure of "state" |
*/ |
*/ |
|
|
int mkposcl( state ) |
int mkposcl (state) |
int state; |
int state; |
{ |
{ |
int eps; |
int eps; |
|
|
if ( SUPER_FREE_EPSILON(finalst[state]) ) |
if (SUPER_FREE_EPSILON (finalst[state])) { |
{ |
mkxtion (finalst[state], state); |
mkxtion( finalst[state], state ); |
|
return state; |
return state; |
} |
} |
|
|
else |
else { |
{ |
eps = mkstate (SYM_EPSILON); |
eps = mkstate( SYM_EPSILON ); |
mkxtion (eps, state); |
mkxtion( eps, state ); |
return link_machines (state, eps); |
return link_machines( state, eps ); |
|
} |
|
} |
} |
|
} |
|
|
|
|
/* mkrep - make a replicated machine |
/* mkrep - make a replicated machine |
|
|
* number of times to "ub" number of times |
* number of times to "ub" number of times |
* |
* |
* note |
* note |
* if "ub" is INFINITY then "new" matches "lb" or more occurrences of "mach" |
* if "ub" is INFINITE_REPEAT then "new" matches "lb" or more occurrences of "mach" |
*/ |
*/ |
|
|
int mkrep( mach, lb, ub ) |
int mkrep (mach, lb, ub) |
int mach, lb, ub; |
int mach, lb, ub; |
{ |
{ |
int base_mach, tail, copy, i; |
int base_mach, tail, copy, i; |
|
|
base_mach = copysingl( mach, lb - 1 ); |
base_mach = copysingl (mach, lb - 1); |
|
|
if ( ub == INFINITY ) |
if (ub == INFINITE_REPEAT) { |
{ |
copy = dupmachine (mach); |
copy = dupmachine( mach ); |
mach = link_machines (mach, |
mach = link_machines( mach, |
link_machines (base_mach, |
link_machines( base_mach, mkclos( copy ) ) ); |
mkclos (copy))); |
} |
} |
|
|
else |
else { |
{ |
tail = mkstate (SYM_EPSILON); |
tail = mkstate( SYM_EPSILON ); |
|
|
|
for ( i = lb; i < ub; ++i ) |
for (i = lb; i < ub; ++i) { |
{ |
copy = dupmachine (mach); |
copy = dupmachine( mach ); |
tail = mkopt (link_machines (copy, tail)); |
tail = mkopt( link_machines( copy, tail ) ); |
|
} |
|
|
|
mach = link_machines( mach, link_machines( base_mach, tail ) ); |
|
} |
} |
|
|
return mach; |
mach = |
|
link_machines (mach, |
|
link_machines (base_mach, tail)); |
} |
} |
|
|
|
return mach; |
|
} |
|
|
|
|
/* mkstate - create a state with a transition on a given symbol |
/* mkstate - create a state with a transition on a given symbol |
* |
* |
* synopsis |
* synopsis |
|
|
* that it admittedly is) |
* that it admittedly is) |
*/ |
*/ |
|
|
int mkstate( sym ) |
int mkstate (sym) |
int sym; |
int sym; |
{ |
{ |
if ( ++lastnfa >= current_mns ) |
if (++lastnfa >= current_mns) { |
{ |
if ((current_mns += MNS_INCREMENT) >= maximum_mns) |
if ( (current_mns += MNS_INCREMENT) >= MAXIMUM_MNS ) |
lerrif (_ |
lerrif( |
("input rules are too complicated (>= %d NFA states)"), |
_( "input rules are too complicated (>= %d NFA states)" ), |
current_mns); |
current_mns ); |
|
|
|
++num_reallocs; |
++num_reallocs; |
|
|
firstst = reallocate_integer_array( firstst, current_mns ); |
firstst = reallocate_integer_array (firstst, current_mns); |
lastst = reallocate_integer_array( lastst, current_mns ); |
lastst = reallocate_integer_array (lastst, current_mns); |
finalst = reallocate_integer_array( finalst, current_mns ); |
finalst = reallocate_integer_array (finalst, current_mns); |
transchar = reallocate_integer_array( transchar, current_mns ); |
transchar = |
trans1 = reallocate_integer_array( trans1, current_mns ); |
reallocate_integer_array (transchar, current_mns); |
trans2 = reallocate_integer_array( trans2, current_mns ); |
trans1 = reallocate_integer_array (trans1, current_mns); |
accptnum = reallocate_integer_array( accptnum, current_mns ); |
trans2 = reallocate_integer_array (trans2, current_mns); |
|
accptnum = |
|
reallocate_integer_array (accptnum, current_mns); |
assoc_rule = |
assoc_rule = |
reallocate_integer_array( assoc_rule, current_mns ); |
reallocate_integer_array (assoc_rule, current_mns); |
state_type = |
state_type = |
reallocate_integer_array( state_type, current_mns ); |
reallocate_integer_array (state_type, current_mns); |
} |
} |
|
|
firstst[lastnfa] = lastnfa; |
firstst[lastnfa] = lastnfa; |
finalst[lastnfa] = lastnfa; |
finalst[lastnfa] = lastnfa; |
|
|
* elsewhere in the input). |
* elsewhere in the input). |
*/ |
*/ |
|
|
if ( sym < 0 ) |
if (sym < 0) { |
{ |
|
/* We don't have to update the equivalence classes since |
/* We don't have to update the equivalence classes since |
* that was already done when the ccl was created for the |
* that was already done when the ccl was created for the |
* first time. |
* first time. |
*/ |
*/ |
} |
} |
|
|
else if ( sym == SYM_EPSILON ) |
else if (sym == SYM_EPSILON) |
++numeps; |
++numeps; |
|
|
else |
else { |
{ |
check_char (sym); |
check_char( sym ); |
|
|
|
if ( useecs ) |
if (useecs) |
/* Map NUL's to csize. */ |
/* Map NUL's to csize. */ |
mkechar( sym ? sym : csize, nextecm, ecgroup ); |
mkechar (sym ? sym : csize, nextecm, ecgroup); |
} |
} |
|
|
return lastnfa; |
return lastnfa; |
} |
} |
|
|
|
|
/* mkxtion - make a transition from one state to another |
/* mkxtion - make a transition from one state to another |
|
|
* stateto - the state to which the transition is to be made |
* stateto - the state to which the transition is to be made |
*/ |
*/ |
|
|
void mkxtion( statefrom, stateto ) |
void mkxtion (statefrom, stateto) |
int statefrom, stateto; |
int statefrom, stateto; |
{ |
{ |
if ( trans1[statefrom] == NO_TRANSITION ) |
if (trans1[statefrom] == NO_TRANSITION) |
trans1[statefrom] = stateto; |
trans1[statefrom] = stateto; |
|
|
else if ( (transchar[statefrom] != SYM_EPSILON) || |
else if ((transchar[statefrom] != SYM_EPSILON) || |
(trans2[statefrom] != NO_TRANSITION) ) |
(trans2[statefrom] != NO_TRANSITION)) |
flexfatal( _( "found too many transitions in mkxtion()" ) ); |
flexfatal (_("found too many transitions in mkxtion()")); |
|
|
else |
else { /* second out-transition for an epsilon state */ |
{ /* second out-transition for an epsilon state */ |
|
++eps2; |
++eps2; |
trans2[statefrom] = stateto; |
trans2[statefrom] = stateto; |
} |
|
} |
} |
|
} |
|
|
/* new_rule - initialize for a new rule */ |
/* new_rule - initialize for a new rule */ |
|
|
void new_rule() |
void new_rule () |
{ |
{ |
if ( ++num_rules >= current_max_rules ) |
if (++num_rules >= current_max_rules) { |
{ |
|
++num_reallocs; |
++num_reallocs; |
current_max_rules += MAX_RULES_INCREMENT; |
current_max_rules += MAX_RULES_INCREMENT; |
rule_type = reallocate_integer_array( rule_type, |
rule_type = reallocate_integer_array (rule_type, |
current_max_rules ); |
current_max_rules); |
rule_linenum = reallocate_integer_array( rule_linenum, |
rule_linenum = reallocate_integer_array (rule_linenum, |
current_max_rules ); |
current_max_rules); |
rule_useful = reallocate_integer_array( rule_useful, |
rule_useful = reallocate_integer_array (rule_useful, |
current_max_rules ); |
current_max_rules); |
} |
rule_has_nl = reallocate_bool_array (rule_has_nl, |
|
current_max_rules); |
|
} |
|
|
if ( num_rules > MAX_RULE ) |
if (num_rules > MAX_RULE) |
lerrif( _( "too many rules (> %d)!" ), MAX_RULE ); |
lerrif (_("too many rules (> %d)!"), MAX_RULE); |
|
|
rule_linenum[num_rules] = linenum; |
rule_linenum[num_rules] = linenum; |
rule_useful[num_rules] = false; |
rule_useful[num_rules] = false; |
} |
rule_has_nl[num_rules] = false; |
|
} |