summaryrefslogtreecommitdiffstats
path: root/rx/rxspencer.c
diff options
context:
space:
mode:
Diffstat (limited to 'rx/rxspencer.c')
-rw-r--r--rx/rxspencer.c1191
1 files changed, 1191 insertions, 0 deletions
diff --git a/rx/rxspencer.c b/rx/rxspencer.c
new file mode 100644
index 00000000..0e2805c6
--- /dev/null
+++ b/rx/rxspencer.c
@@ -0,0 +1,1191 @@
+/* Copyright (C) 1995, 1996 Tom Lord
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this software; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+
+#include <stdio.h>
+#include "rxall.h"
+#include "rxspencer.h"
+#include "rxsimp.h"
+
+
+
+static char * silly_hack_2 = 0;
+
+struct rx_solutions rx_no_solutions;
+
+#ifdef __STDC__
+struct rx_solutions *
+rx_make_solutions (struct rx_registers * regs, struct rx_unfaniverse * verse, struct rexp_node * expression, struct rexp_node ** subexps, int cset_size, int start, int end, rx_vmfn vmfn, rx_contextfn contextfn, void * closure)
+#else
+struct rx_solutions *
+rx_make_solutions (regs, verse, expression, subexps, cset_size,
+ start, end, vmfn, contextfn, closure)
+ struct rx_registers * regs;
+ struct rx_unfaniverse * verse;
+ struct rexp_node * expression;
+ struct rexp_node ** subexps;
+ int cset_size;
+ int start;
+ int end;
+ rx_vmfn vmfn;
+ rx_contextfn contextfn;
+ void * closure;
+#endif
+{
+ struct rx_solutions * solns;
+
+ if ( expression
+ && (expression->len >= 0)
+ && (expression->len != (end - start)))
+ return &rx_no_solutions;
+
+ if (silly_hack_2)
+ {
+ solns = (struct rx_solutions *)silly_hack_2;
+ silly_hack_2 = 0;
+ }
+ else
+ solns = (struct rx_solutions *)malloc (sizeof (*solns));
+ if (!solns)
+ return 0;
+ rx_bzero ((char *)solns, sizeof (*solns));
+
+ solns->step = 0;
+ solns->cset_size = cset_size;
+ solns->subexps = subexps;
+ solns->exp = expression;
+ rx_save_rexp (expression);
+ solns->verse = verse;
+ solns->regs = regs;
+ solns->start = start;
+ solns->end = end;
+ solns->vmfn = vmfn;
+ solns->contextfn = contextfn;
+ solns->closure = closure;
+
+ if (!solns->exp || !solns->exp->observed)
+ {
+ solns->dfa = rx_unfa (verse, expression, cset_size);
+ if (!solns->dfa)
+ goto err_return;
+ rx_init_system (&solns->match_engine, solns->dfa->nfa);
+
+ if (rx_yes != rx_start_superstate (&solns->match_engine))
+ goto err_return;
+ }
+ else
+ {
+ struct rexp_node * simplified;
+ int status;
+ status = rx_simple_rexp (&simplified, cset_size, solns->exp, subexps);
+ if (status)
+ goto err_return;
+ solns->dfa = rx_unfa (verse, simplified, cset_size);
+ if (!solns->dfa)
+ {
+ rx_free_rexp (simplified);
+ goto err_return;
+ }
+ rx_init_system (&solns->match_engine, solns->dfa->nfa);
+ if (rx_yes != rx_start_superstate (&solns->match_engine))
+ goto err_return;
+ rx_free_rexp (simplified);
+ }
+
+ if (expression && ( (expression->type == r_concat)
+ || (expression->type == r_plus)
+ || (expression->type == r_star)
+ || (expression->type == r_interval)))
+ {
+ struct rexp_node * subexp;
+
+ subexp = solns->exp->params.pair.left;
+
+ if (!subexp || !subexp->observed)
+ {
+ solns->left_dfa = rx_unfa (solns->verse, subexp, solns->cset_size);
+ }
+ else
+ {
+ struct rexp_node * simplified;
+ int status;
+ status = rx_simple_rexp (&simplified, solns->cset_size, subexp, solns->subexps);
+ if (status)
+ goto err_return;
+ solns->left_dfa = rx_unfa (solns->verse, simplified, solns->cset_size);
+ rx_free_rexp (simplified);
+ }
+
+ if (!solns->left_dfa)
+ goto err_return;
+ rx_bzero ((char *)&solns->left_match_engine, sizeof (solns->left_match_engine));
+ rx_init_system (&solns->left_match_engine, solns->left_dfa->nfa);
+ }
+
+ return solns;
+
+ err_return:
+ rx_free_rexp (solns->exp);
+ free (solns);
+ return 0;
+}
+
+
+
+#ifdef __STDC__
+void
+rx_free_solutions (struct rx_solutions * solns)
+#else
+void
+rx_free_solutions (solns)
+ struct rx_solutions * solns;
+#endif
+{
+ if (!solns)
+ return;
+
+ if (solns == &rx_no_solutions)
+ return;
+
+ if (solns->left)
+ {
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ }
+
+ if (solns->right)
+ {
+ rx_free_solutions (solns->right);
+ solns->right = 0;
+ }
+
+ if (solns->dfa)
+ {
+ rx_free_unfa (solns->dfa);
+ solns->dfa = 0;
+ }
+ if (solns->left_dfa)
+ {
+ rx_terminate_system (&solns->left_match_engine);
+ rx_free_unfa (solns->left_dfa);
+ solns->left_dfa = 0;
+ }
+
+ rx_terminate_system (&solns->match_engine);
+
+ if (solns->exp)
+ {
+ rx_free_rexp (solns->exp);
+ solns->exp = 0;
+ }
+
+ if (!silly_hack_2)
+ silly_hack_2 = (char *)solns;
+ else
+ free (solns);
+}
+
+
+#ifdef __STDC__
+static enum rx_answers
+rx_solution_fit_p (struct rx_solutions * solns)
+#else
+static enum rx_answers
+rx_solution_fit_p (solns)
+ struct rx_solutions * solns;
+#endif
+{
+ unsigned const char * burst;
+ int burst_addr;
+ int burst_len;
+ int burst_end_addr;
+ int rel_pos_in_burst;
+ enum rx_answers vmstat;
+ int current_pos;
+
+ current_pos = solns->start;
+ next_burst:
+ vmstat = solns->vmfn (solns->closure,
+ &burst, &burst_len, &burst_addr,
+ current_pos, solns->end,
+ current_pos);
+
+ if (vmstat != rx_yes)
+ return vmstat;
+
+ rel_pos_in_burst = current_pos - burst_addr;
+ burst_end_addr = burst_addr + burst_len;
+
+ if (burst_end_addr >= solns->end)
+ {
+ enum rx_answers fit_status;
+ fit_status = rx_fit_p (&solns->match_engine,
+ burst + rel_pos_in_burst,
+ solns->end - current_pos);
+ return fit_status;
+ }
+ else
+ {
+ enum rx_answers fit_status;
+ fit_status = rx_advance (&solns->match_engine,
+ burst + rel_pos_in_burst,
+ burst_len - rel_pos_in_burst);
+ if (fit_status != rx_yes)
+ {
+ return fit_status;
+ }
+ else
+ {
+ current_pos += burst_len - rel_pos_in_burst;
+ goto next_burst;
+ }
+ }
+}
+
+
+#ifdef __STDC__
+static enum rx_answers
+rx_solution_fit_str_p (struct rx_solutions * solns)
+#else
+static enum rx_answers
+rx_solution_fit_str_p (solns)
+ struct rx_solutions * solns;
+#endif
+{
+ int current_pos;
+ unsigned const char * burst;
+ int burst_addr;
+ int burst_len;
+ int burst_end_addr;
+ int rel_pos_in_burst;
+ enum rx_answers vmstat;
+ int count;
+ unsigned char * key;
+
+
+ current_pos = solns->start;
+ count = solns->exp->params.cstr.len;
+ key = (unsigned char *)solns->exp->params.cstr.contents;
+
+ next_burst:
+ vmstat = solns->vmfn (solns->closure,
+ &burst, &burst_len, &burst_addr,
+ current_pos, solns->end,
+ current_pos);
+
+ if (vmstat != rx_yes)
+ return vmstat;
+
+ rel_pos_in_burst = current_pos - burst_addr;
+ burst_end_addr = burst_addr + burst_len;
+
+ {
+ unsigned const char * pos;
+
+ pos = burst + rel_pos_in_burst;
+
+ if (burst_end_addr >= solns->end)
+ {
+ while (count)
+ {
+ if (*pos != *key)
+ return rx_no;
+ ++pos;
+ ++key;
+ --count;
+ }
+ return rx_yes;
+ }
+ else
+ {
+ int part_count;
+ int part_count_init;
+
+ part_count_init = burst_len - rel_pos_in_burst;
+ part_count = part_count_init;
+ while (part_count)
+ {
+ if (*pos != *key)
+ return rx_no;
+ ++pos;
+ ++key;
+ --part_count;
+ }
+ count -= part_count_init;
+ current_pos += burst_len - rel_pos_in_burst;
+ goto next_burst;
+ }
+ }
+}
+
+
+
+
+#if 0
+#ifdef __STDC__
+int
+rx_best_end_guess (struct rx_solutions * solns, struct rexp_node * exp, int bound)
+#else
+int
+rx_best_end_guess (solns, exp, bound)
+ struct rx_solutions * solns;
+ struct rexp_node * exp;
+ int bound;
+#endif
+{
+ int current_pos;
+ unsigned const char * burst;
+ int burst_addr;
+ int burst_len;
+ int burst_end_addr;
+ int rel_pos_in_burst;
+ int best_guess;
+ enum rx_answers vmstat;
+
+#if 0
+ unparse_print_rexp (256, solns->exp);
+ printf ("\n");
+ unparse_print_rexp (256, exp);
+ printf ("\nbound %d \n", bound);
+#endif
+
+ if (rx_yes != rx_start_superstate (&solns->left_match_engine))
+ {
+ return bound - 1;
+ }
+ best_guess = current_pos = solns->start;
+
+ next_burst:
+#if 0
+ printf (" best_guess %d\n", best_guess);
+#endif
+ vmstat = solns->vmfn (solns->closure,
+ &burst, &burst_len, &burst_addr,
+ current_pos, bound,
+ current_pos);
+#if 0
+ printf (" str>%s\n", burst);
+#endif
+ if (vmstat != rx_yes)
+ {
+ return bound - 1;
+ }
+
+ rel_pos_in_burst = current_pos - burst_addr;
+ burst_end_addr = burst_addr + burst_len;
+
+ if (burst_end_addr > bound)
+ {
+ burst_end_addr = bound;
+ burst_len = bound - burst_addr;
+ }
+
+ {
+ int amt_advanced;
+
+#if 0
+ printf (" rel_pos_in_burst %d burst_len %d\n", rel_pos_in_burst, burst_len);
+#endif
+ while (rel_pos_in_burst < burst_len)
+ {
+ amt_advanced= rx_advance_to_final (&solns->left_match_engine,
+ burst + rel_pos_in_burst,
+ burst_len - rel_pos_in_burst);
+#if 0
+ printf (" amt_advanced %d", amt_advanced);
+#endif
+ if (amt_advanced < 0)
+ {
+ return bound - 1;
+ }
+ current_pos += amt_advanced;
+ rel_pos_in_burst += amt_advanced;
+ if (solns->left_match_engine.final_tag)
+ best_guess = current_pos;
+#if 0
+ printf (" best_guess %d\n", best_guess);
+ printf (" current_pos %d\n", current_pos);
+#endif
+ if (amt_advanced == 0)
+ {
+ return best_guess;
+ }
+ }
+ if (current_pos == bound)
+ {
+ return best_guess;
+ }
+ goto next_burst;
+ }
+}
+#endif
+
+
+
+#ifdef __STDC__
+enum rx_answers
+rx_next_solution (struct rx_solutions * solns)
+#else
+enum rx_answers
+rx_next_solution (solns)
+ struct rx_solutions * solns;
+#endif
+{
+ if (!solns)
+ return rx_bogus;
+
+ if (solns == &rx_no_solutions)
+ {
+ return rx_no;
+ }
+
+ if (!solns->exp)
+ {
+ if (solns->step != 0)
+ {
+ return rx_no;
+ }
+ else
+ {
+ solns->step = 1;
+ solns->final_tag = 1;
+ return (solns->start == solns->end
+ ? rx_yes
+ : rx_no);
+ }
+ }
+ else if ( (solns->exp->len >= 0)
+ && (solns->exp->len != (solns->end - solns->start)))
+ {
+ return rx_no;
+ }
+ else if (!solns->exp->observed)
+ {
+ if (solns->step != 0)
+ {
+ return rx_no;
+ }
+ else if (solns->exp->type == r_string)
+ {
+ enum rx_answers ans;
+ ans = rx_solution_fit_str_p (solns);
+ solns->final_tag = 1;
+ solns->step = -1;
+ return ans;
+ }
+ else
+ {
+ enum rx_answers ans;
+ ans = rx_solution_fit_p (solns);
+ solns->final_tag = solns->match_engine.final_tag;
+ solns->step = -1;
+ return ans;
+ }
+ }
+ else if (solns->exp->observed)
+ {
+ enum rx_answers fit_p;
+ switch (solns->step)
+ {
+ case -2:
+ if (solns->exp->params.intval)
+ {
+ solns->regs[solns->exp->params.intval].rm_so = solns->saved_rm_so;
+ solns->regs[solns->exp->params.intval].rm_eo = solns->saved_rm_eo;
+ }
+ return rx_no;
+
+ case -1:
+ return rx_no;
+
+ case 0:
+ fit_p = rx_solution_fit_p (solns);
+ /* Set final_tag here because this rough fit test
+ * may be all the matching that gets done.
+ * For example, consider a paren node containing
+ * a true regular expression ending with a cut
+ * operator.
+ */
+ solns->final_tag = solns->match_engine.final_tag;
+ switch (fit_p)
+ {
+ case rx_no:
+ solns->step = -1;
+ return rx_no;
+ case rx_yes:
+ solns->step = 1;
+ goto resolve_fit;
+ case rx_bogus:
+ default:
+ solns->step = -1;
+ return fit_p;
+ }
+
+ default:
+ resolve_fit:
+ switch (solns->exp->type)
+ {
+ case r_cset:
+ case r_string:
+ case r_cut:
+ solns->step = -1;
+ return rx_bogus;
+
+ case r_parens:
+ {
+ enum rx_answers paren_stat;
+ switch (solns->step)
+ {
+ case 1:
+ if (solns->exp->params.intval)
+ {
+ solns->saved_rm_so = solns->regs[solns->exp->params.intval].rm_so;
+ solns->saved_rm_eo = solns->regs[solns->exp->params.intval].rm_eo;
+ }
+
+ if ( !solns->exp->params.pair.left
+ || !solns->exp->params.pair.left->observed)
+ {
+ if (solns->exp->params.intval)
+ {
+ solns->regs[solns->exp->params.intval].rm_so = solns->start;
+ solns->regs[solns->exp->params.intval].rm_eo = solns->end;
+ }
+ solns->step = -2;
+ /* Keep the final_tag from the fit_p test. */
+ return rx_yes;
+ }
+ else
+ {
+ solns->left = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp->params.pair.left,
+ solns->subexps,
+ solns->cset_size,
+ solns->start,
+ solns->end,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ if (!solns->left)
+ {
+ solns->step = -1;
+ return rx_bogus;
+ }
+ }
+ solns->step = 2;
+ /* fall through */
+
+ case 2:
+ if (solns->exp->params.intval)
+ {
+ solns->regs[solns->exp->params.intval].rm_so = solns->saved_rm_so;
+ solns->regs[solns->exp->params.intval].rm_eo = solns->saved_rm_eo;
+ }
+
+ paren_stat = rx_next_solution (solns->left);
+ if (paren_stat == rx_yes)
+ {
+ if (solns->exp->params.intval)
+ {
+ solns->regs[solns->exp->params.intval].rm_so = solns->start;
+ solns->regs[solns->exp->params.intval].rm_eo = solns->end;
+ }
+ solns->final_tag = solns->left->final_tag;
+ return rx_yes;
+ }
+ else
+ {
+ solns->step = -1;
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ if (solns->exp->params.intval)
+ {
+ solns->regs[solns->exp->params.intval].rm_so = solns->saved_rm_so;
+ solns->regs[solns->exp->params.intval].rm_eo = solns->saved_rm_eo;
+ }
+ return paren_stat;
+ }
+ }
+ }
+
+
+ case r_opt:
+ {
+ enum rx_answers opt_stat;
+ switch (solns->step)
+ {
+ case 1:
+ solns->left = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp->params.pair.left,
+ solns->subexps,
+ solns->cset_size,
+ solns->start,
+ solns->end,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ if (!solns->left)
+ {
+ solns->step = -1;
+ return rx_bogus;
+ }
+ solns->step = 2;
+ /* fall through */
+
+ case 2:
+ opt_stat = rx_next_solution (solns->left);
+ if (opt_stat == rx_yes)
+ {
+ solns->final_tag = solns->left->final_tag;
+ return rx_yes;
+ }
+ else
+ {
+ solns->step = -1;
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ return ((solns->start == solns->end)
+ ? rx_yes
+ : rx_no);
+ }
+
+ }
+ }
+
+ case r_alternate:
+ {
+ enum rx_answers alt_stat;
+ switch (solns->step)
+ {
+ case 1:
+ solns->left = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp->params.pair.left,
+ solns->subexps,
+ solns->cset_size,
+ solns->start,
+ solns->end,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ if (!solns->left)
+ {
+ solns->step = -1;
+ return rx_bogus;
+ }
+ solns->step = 2;
+ /* fall through */
+
+ case 2:
+ alt_stat = rx_next_solution (solns->left);
+
+ if (alt_stat == rx_yes)
+ {
+ solns->final_tag = solns->left->final_tag;
+ return alt_stat;
+ }
+ else
+ {
+ solns->step = 3;
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ /* fall through */
+ }
+
+ case 3:
+ solns->right = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp->params.pair.right,
+ solns->subexps,
+ solns->cset_size,
+ solns->start,
+ solns->end,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ if (!solns->right)
+ {
+ solns->step = -1;
+ return rx_bogus;
+ }
+ solns->step = 4;
+ /* fall through */
+
+ case 4:
+ alt_stat = rx_next_solution (solns->right);
+
+ if (alt_stat == rx_yes)
+ {
+ solns->final_tag = solns->right->final_tag;
+ return alt_stat;
+ }
+ else
+ {
+ solns->step = -1;
+ rx_free_solutions (solns->right);
+ solns->right = 0;
+ return alt_stat;
+ }
+ }
+ }
+
+ case r_concat:
+ {
+ switch (solns->step)
+ {
+ enum rx_answers concat_stat;
+ case 1:
+ solns->split_guess = solns->end;
+#if 0
+ solns->split_guess = ((solns->end - solns->start) > RX_MANY_CASES
+ ? rx_best_end_guess (solns,
+ solns->exp->params.pair.left, solns->end)
+ : solns->end);
+#endif
+
+ concat_split_guess_loop:
+ solns->left = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp->params.pair.left,
+ solns->subexps,
+ solns->cset_size,
+ solns->start,
+ solns->split_guess,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ if (!solns->left)
+ {
+ solns->step = -1;
+ return rx_bogus;
+ }
+ solns->step = 2;
+
+ case 2:
+ concat_try_next_left_match:
+
+ concat_stat = rx_next_solution (solns->left);
+ if (concat_stat != rx_yes)
+ {
+ rx_free_solutions (solns->left);
+ rx_free_solutions (solns->right);
+ solns->left = solns->right = 0;
+ solns->split_guess = solns->split_guess - 1;
+#if 0
+ solns->split_guess = ((solns->split_guess - solns->start) > RX_MANY_CASES
+ ? rx_best_end_guess (solns,
+ solns->exp->params.pair.left,
+ solns->split_guess - 1)
+ : solns->split_guess - 1);
+#endif
+ if (solns->split_guess >= solns->start)
+ goto concat_split_guess_loop;
+ else
+ {
+ solns->step = -1;
+ return concat_stat;
+ }
+ }
+ else
+ {
+ solns->step = 3;
+ /* fall through */
+ }
+
+ case 3:
+ solns->right = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp->params.pair.right,
+ solns->subexps,
+ solns->cset_size,
+ solns->split_guess,
+ solns->end,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ if (!solns->right)
+ {
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ solns->step = -1;
+ return rx_bogus;
+ }
+
+ solns->step = 4;
+ /* fall through */
+
+ case 4:
+ /* concat_try_next_right_match: */
+
+ concat_stat = rx_next_solution (solns->right);
+ if (concat_stat == rx_yes)
+ {
+ solns->final_tag = solns->right->final_tag;
+ return concat_stat;
+ }
+ else if (concat_stat == rx_no)
+ {
+ rx_free_solutions (solns->right);
+ solns->right = 0;
+ solns->step = 2;
+ goto concat_try_next_left_match;
+ }
+ else /* concat_stat == rx_bogus */
+ {
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ rx_free_solutions (solns->right);
+ solns->right = 0;
+ solns->step = -1;
+ return concat_stat;
+ }
+ }
+ }
+
+
+ case r_plus:
+ case r_star:
+ {
+ switch (solns->step)
+ {
+ enum rx_answers star_stat;
+ case 1:
+ solns->split_guess = solns->end;
+#if 0
+ solns->split_guess = ((solns->end - solns->start) > RX_MANY_CASES
+ ? rx_best_end_guess (solns,
+ solns->exp->params.pair.left, solns->end)
+ : solns->end);
+#endif
+
+ star_split_guess_loop:
+ solns->left = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp->params.pair.left,
+ solns->subexps,
+ solns->cset_size,
+ solns->start,
+ solns->split_guess,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ if (!solns->left)
+ {
+ solns->step = -1;
+ return rx_bogus;
+ }
+ solns->step = 2;
+
+ case 2:
+ star_try_next_left_match:
+
+ star_stat = rx_next_solution (solns->left);
+ if (star_stat != rx_yes)
+ {
+ rx_free_solutions (solns->left);
+ rx_free_solutions (solns->right);
+ solns->left = solns->right = 0;
+ solns->split_guess = solns->split_guess - 1;
+#if 0
+ solns->split_guess = ((solns->split_guess - solns->start) > RX_MANY_CASES
+ ? rx_best_end_guess (solns,
+ solns->exp->params.pair.left,
+ solns->split_guess - 1)
+ : solns->split_guess - 1);
+#endif
+ if (solns->split_guess >= solns->start)
+ goto star_split_guess_loop;
+ else
+ {
+ solns->step = -1;
+
+ if ( (solns->exp->type == r_star)
+ && (solns->start == solns->end)
+ && (star_stat == rx_no))
+ {
+ solns->final_tag = 1;
+ return rx_yes;
+ }
+ else
+ return star_stat;
+ }
+ }
+ else
+ {
+ solns->step = 3;
+ /* fall through */
+ }
+
+
+ if (solns->split_guess == solns->end)
+ {
+ solns->final_tag = solns->left->final_tag;
+ return rx_yes;
+ }
+
+ case 3:
+ solns->right = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp,
+ solns->subexps,
+ solns->cset_size,
+ solns->split_guess,
+ solns->end,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ if (!solns->right)
+ {
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ solns->step = -1;
+ return rx_bogus;
+ }
+
+ solns->step = 4;
+ /* fall through */
+
+ case 4:
+ /* star_try_next_right_match: */
+
+ star_stat = rx_next_solution (solns->right);
+ if (star_stat == rx_yes)
+ {
+ solns->final_tag = solns->right->final_tag;
+ return star_stat;
+ }
+ else if (star_stat == rx_no)
+ {
+ rx_free_solutions (solns->right);
+ solns->right = 0;
+ solns->step = 2;
+ goto star_try_next_left_match;
+ }
+ else /* star_stat == rx_bogus */
+ {
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ rx_free_solutions (solns->right);
+ solns->right = 0;
+ solns->step = -1;
+ return star_stat;
+ }
+ }
+ }
+
+ case r_interval:
+ {
+ switch (solns->step)
+ {
+ enum rx_answers interval_stat;
+
+ case 1:
+ /* If the interval permits nothing,
+ * return immediately.
+ */
+ if (solns->exp->params.intval2 < solns->interval_x)
+ {
+ solns->step = -1;
+ return rx_no;
+ }
+
+ /* If the interval permits only 0 iterations,
+ * return immediately. Success depends on the
+ * emptiness of the match.
+ */
+ if ( (solns->exp->params.intval2 == solns->interval_x)
+ && (solns->exp->params.intval <= solns->interval_x))
+ {
+ solns->step = -1;
+ solns->final_tag = 1;
+ return ((solns->start == solns->end)
+ ? rx_yes
+ : rx_no);
+ }
+
+ /* The interval permits at most 0 iterations,
+ * but also requires more. A bug.
+ */
+ if (solns->exp->params.intval2 == solns->interval_x)
+ {
+ /* indicates a regexp compilation error, actually */
+ solns->step = -1;
+ return rx_bogus;
+ }
+
+ solns->split_guess = solns->end;
+#if 0
+ solns->split_guess = ((solns->end - solns->start) > RX_MANY_CASES
+ ? rx_best_end_guess (solns,
+ solns->exp->params.pair.left, solns->end)
+ : solns->end);
+#endif
+
+ /* The interval permits more than 0 iterations.
+ * If it permits 0 and the match is to be empty,
+ * the trivial match is the most preferred answer.
+ */
+ if (solns->exp->params.intval <= solns->interval_x)
+ {
+ solns->step = 2;
+ if (solns->start == solns->end)
+ {
+ solns->final_tag = 1;
+ return rx_yes;
+ }
+ /* If this isn't a trivial match, or if the trivial match
+ * is rejected, look harder.
+ */
+ }
+
+ case 2:
+ interval_split_guess_loop:
+ /* The match requires at least one iteration, either because
+ * there are characters to match, or because the interval starts
+ * above 0.
+ *
+ * Look for the first iteration:
+ */
+ solns->left = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp->params.pair.left,
+ solns->subexps,
+ solns->cset_size,
+ solns->start,
+ solns->split_guess,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ if (!solns->left)
+ {
+ solns->step = -1;
+ return rx_bogus;
+ }
+ solns->step = 3;
+
+ case 3:
+ interval_try_next_left_match:
+
+ interval_stat = rx_next_solution (solns->left);
+ if (interval_stat != rx_yes)
+ {
+ rx_free_solutions (solns->left);
+ rx_free_solutions (solns->right);
+ solns->left = solns->right = 0;
+ solns->split_guess = solns->split_guess - 1;
+#if 0
+ solns->split_guess = ((solns->split_guess - solns->start) > RX_MANY_CASES
+ ? rx_best_end_guess (solns,
+ solns->exp->params.pair.left,
+ solns->split_guess - 1)
+ : solns->split_guess - 1);
+#endif
+ if (solns->split_guess >= solns->start)
+ goto interval_split_guess_loop;
+ else
+ {
+ solns->step = -1;
+ return interval_stat;
+ }
+ }
+ else
+ {
+ solns->step = 4;
+ /* fall through */
+ }
+
+ case 4:
+ {
+ /* After matching one required iteration, construct a smaller
+ * interval and try to match that against the rest.
+ *
+ * To avoid thwarting unfa caching, instead of building a new
+ * rexp node with different interval extents, we keep interval_x
+ * in each solns structure to keep track of the number of
+ * iterations matched so far.
+ */
+ solns->right = rx_make_solutions (solns->regs,
+ solns->verse,
+ solns->exp,
+ solns->subexps,
+ solns->cset_size,
+ solns->split_guess,
+ solns->end,
+ solns->vmfn,
+ solns->contextfn,
+ solns->closure);
+ solns->right->interval_x = solns->interval_x + 1;
+ }
+ if (!solns->right)
+ {
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ solns->step = -1;
+ return rx_bogus;
+ }
+
+ solns->step = 5;
+ /* fall through */
+
+ case 5:
+ /* interval_try_next_right_match: */
+
+ interval_stat = rx_next_solution (solns->right);
+ if (interval_stat == rx_yes)
+ {
+ solns->final_tag = solns->right->final_tag;
+ return interval_stat;
+ }
+ else if (interval_stat == rx_no)
+ {
+ rx_free_solutions (solns->right);
+ solns->right = 0;
+ solns->step = 2;
+ goto interval_try_next_left_match;
+ }
+ else /* interval_stat == rx_bogus */
+ {
+ rx_free_solutions (solns->left);
+ solns->left = 0;
+ rx_free_solutions (solns->right);
+ solns->right = 0;
+ solns->step = -1;
+ return interval_stat;
+ }
+ }
+ }
+
+ case r_context:
+ {
+ solns->step = -1;
+ solns->final_tag = 1;
+ return solns->contextfn (solns->closure,
+ solns->exp,
+ solns->start, solns->end,
+ solns->regs);
+ }
+
+
+ }
+ }
+ return rx_bogus;
+ }
+}