os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/regcomp.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/regcomp.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,2179 @@
     1.4 +/*
     1.5 + * re_*comp and friends - compile REs
     1.6 + * This file #includes several others (see the bottom).
     1.7 + *
     1.8 + * Copyright (c) 1998, 1999 Henry Spencer.  All rights reserved.
     1.9 + * 
    1.10 + * Development of this software was funded, in part, by Cray Research Inc.,
    1.11 + * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
    1.12 + * Corporation, none of whom are responsible for the results.  The author
    1.13 + * thanks all of them. 
    1.14 + * 
    1.15 + * Redistribution and use in source and binary forms -- with or without
    1.16 + * modification -- are permitted for any purpose, provided that
    1.17 + * redistributions in source form retain this entire copyright notice and
    1.18 + * indicate the origin and nature of any modifications.
    1.19 + * 
    1.20 + * I'd appreciate being given credit for this package in the documentation
    1.21 + * of software which uses it, but that is not a requirement.
    1.22 + * 
    1.23 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
    1.24 + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
    1.25 + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
    1.26 + * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    1.27 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    1.28 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    1.29 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    1.30 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    1.31 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
    1.32 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.33 + *
    1.34 + */
    1.35 +
    1.36 +#include "regguts.h"
    1.37 +
    1.38 +/*
    1.39 + * forward declarations, up here so forward datatypes etc. are defined early
    1.40 + */
    1.41 +/* =====^!^===== begin forwards =====^!^===== */
    1.42 +/* automatically gathered by fwd; do not hand-edit */
    1.43 +/* === regcomp.c === */
    1.44 +int compile _ANSI_ARGS_((regex_t *, CONST chr *, size_t, int));
    1.45 +static VOID moresubs _ANSI_ARGS_((struct vars *, int));
    1.46 +static int freev _ANSI_ARGS_((struct vars *, int));
    1.47 +static VOID makesearch _ANSI_ARGS_((struct vars *, struct nfa *));
    1.48 +static struct subre *parse _ANSI_ARGS_((struct vars *, int, int, struct state *, struct state *));
    1.49 +static struct subre *parsebranch _ANSI_ARGS_((struct vars *, int, int, struct state *, struct state *, int));
    1.50 +static VOID parseqatom _ANSI_ARGS_((struct vars *, int, int, struct state *, struct state *, struct subre *));
    1.51 +static VOID nonword _ANSI_ARGS_((struct vars *, int, struct state *, struct state *));
    1.52 +static VOID word _ANSI_ARGS_((struct vars *, int, struct state *, struct state *));
    1.53 +static int scannum _ANSI_ARGS_((struct vars *));
    1.54 +static VOID repeat _ANSI_ARGS_((struct vars *, struct state *, struct state *, int, int));
    1.55 +static VOID bracket _ANSI_ARGS_((struct vars *, struct state *, struct state *));
    1.56 +static VOID cbracket _ANSI_ARGS_((struct vars *, struct state *, struct state *));
    1.57 +static VOID brackpart _ANSI_ARGS_((struct vars *, struct state *, struct state *));
    1.58 +static chr *scanplain _ANSI_ARGS_((struct vars *));
    1.59 +static VOID leaders _ANSI_ARGS_((struct vars *, struct cvec *));
    1.60 +static VOID onechr _ANSI_ARGS_((struct vars *, pchr, struct state *, struct state *));
    1.61 +static VOID dovec _ANSI_ARGS_((struct vars *, struct cvec *, struct state *, struct state *));
    1.62 +static celt nextleader _ANSI_ARGS_((struct vars *, pchr, pchr));
    1.63 +static VOID wordchrs _ANSI_ARGS_((struct vars *));
    1.64 +static struct subre *subre _ANSI_ARGS_((struct vars *, int, int, struct state *, struct state *));
    1.65 +static VOID freesubre _ANSI_ARGS_((struct vars *, struct subre *));
    1.66 +static VOID freesrnode _ANSI_ARGS_((struct vars *, struct subre *));
    1.67 +static VOID optst _ANSI_ARGS_((struct vars *, struct subre *));
    1.68 +static int numst _ANSI_ARGS_((struct subre *, int));
    1.69 +static VOID markst _ANSI_ARGS_((struct subre *));
    1.70 +static VOID cleanst _ANSI_ARGS_((struct vars *));
    1.71 +static long nfatree _ANSI_ARGS_((struct vars *, struct subre *, FILE *));
    1.72 +static long nfanode _ANSI_ARGS_((struct vars *, struct subre *, FILE *));
    1.73 +static int newlacon _ANSI_ARGS_((struct vars *, struct state *, struct state *, int));
    1.74 +static VOID freelacons _ANSI_ARGS_((struct subre *, int));
    1.75 +static VOID rfree _ANSI_ARGS_((regex_t *));
    1.76 +static VOID dump _ANSI_ARGS_((regex_t *, FILE *));
    1.77 +static VOID dumpst _ANSI_ARGS_((struct subre *, FILE *, int));
    1.78 +static VOID stdump _ANSI_ARGS_((struct subre *, FILE *, int));
    1.79 +static char *stid _ANSI_ARGS_((struct subre *, char *, size_t));
    1.80 +/* === regc_lex.c === */
    1.81 +static VOID lexstart _ANSI_ARGS_((struct vars *));
    1.82 +static VOID prefixes _ANSI_ARGS_((struct vars *));
    1.83 +static VOID lexnest _ANSI_ARGS_((struct vars *, chr *, chr *));
    1.84 +static VOID lexword _ANSI_ARGS_((struct vars *));
    1.85 +static int next _ANSI_ARGS_((struct vars *));
    1.86 +static int lexescape _ANSI_ARGS_((struct vars *));
    1.87 +static chr lexdigits _ANSI_ARGS_((struct vars *, int, int, int));
    1.88 +static int brenext _ANSI_ARGS_((struct vars *, pchr));
    1.89 +static VOID skip _ANSI_ARGS_((struct vars *));
    1.90 +static chr newline _ANSI_ARGS_((NOPARMS));
    1.91 +#ifdef REG_DEBUG
    1.92 +static chr *ch _ANSI_ARGS_((NOPARMS));
    1.93 +#endif
    1.94 +static chr chrnamed _ANSI_ARGS_((struct vars *, chr *, chr *, pchr));
    1.95 +/* === regc_color.c === */
    1.96 +static VOID initcm _ANSI_ARGS_((struct vars *, struct colormap *));
    1.97 +static VOID freecm _ANSI_ARGS_((struct colormap *));
    1.98 +static VOID cmtreefree _ANSI_ARGS_((struct colormap *, union tree *, int));
    1.99 +static color setcolor _ANSI_ARGS_((struct colormap *, pchr, pcolor));
   1.100 +static color maxcolor _ANSI_ARGS_((struct colormap *));
   1.101 +static color newcolor _ANSI_ARGS_((struct colormap *));
   1.102 +static VOID freecolor _ANSI_ARGS_((struct colormap *, pcolor));
   1.103 +static color pseudocolor _ANSI_ARGS_((struct colormap *));
   1.104 +static color subcolor _ANSI_ARGS_((struct colormap *, pchr c));
   1.105 +static color newsub _ANSI_ARGS_((struct colormap *, pcolor));
   1.106 +static VOID subrange _ANSI_ARGS_((struct vars *, pchr, pchr, struct state *, struct state *));
   1.107 +static VOID subblock _ANSI_ARGS_((struct vars *, pchr, struct state *, struct state *));
   1.108 +static VOID okcolors _ANSI_ARGS_((struct nfa *, struct colormap *));
   1.109 +static VOID colorchain _ANSI_ARGS_((struct colormap *, struct arc *));
   1.110 +static VOID uncolorchain _ANSI_ARGS_((struct colormap *, struct arc *));
   1.111 +static int singleton _ANSI_ARGS_((struct colormap *, pchr c));
   1.112 +static VOID rainbow _ANSI_ARGS_((struct nfa *, struct colormap *, int, pcolor, struct state *, struct state *));
   1.113 +static VOID colorcomplement _ANSI_ARGS_((struct nfa *, struct colormap *, int, struct state *, struct state *, struct state *));
   1.114 +#ifdef REG_DEBUG
   1.115 +static VOID dumpcolors _ANSI_ARGS_((struct colormap *, FILE *));
   1.116 +static VOID fillcheck _ANSI_ARGS_((struct colormap *, union tree *, int, FILE *));
   1.117 +static VOID dumpchr _ANSI_ARGS_((pchr, FILE *));
   1.118 +#endif
   1.119 +/* === regc_nfa.c === */
   1.120 +static struct nfa *newnfa _ANSI_ARGS_((struct vars *, struct colormap *, struct nfa *));
   1.121 +static VOID freenfa _ANSI_ARGS_((struct nfa *));
   1.122 +static struct state *newstate _ANSI_ARGS_((struct nfa *));
   1.123 +static struct state *newfstate _ANSI_ARGS_((struct nfa *, int flag));
   1.124 +static VOID dropstate _ANSI_ARGS_((struct nfa *, struct state *));
   1.125 +static VOID freestate _ANSI_ARGS_((struct nfa *, struct state *));
   1.126 +static VOID destroystate _ANSI_ARGS_((struct nfa *, struct state *));
   1.127 +static VOID newarc _ANSI_ARGS_((struct nfa *, int, pcolor, struct state *, struct state *));
   1.128 +static struct arc *allocarc _ANSI_ARGS_((struct nfa *, struct state *));
   1.129 +static VOID freearc _ANSI_ARGS_((struct nfa *, struct arc *));
   1.130 +static struct arc *findarc _ANSI_ARGS_((struct state *, int, pcolor));
   1.131 +static VOID cparc _ANSI_ARGS_((struct nfa *, struct arc *, struct state *, struct state *));
   1.132 +static VOID moveins _ANSI_ARGS_((struct nfa *, struct state *, struct state *));
   1.133 +static VOID copyins _ANSI_ARGS_((struct nfa *, struct state *, struct state *));
   1.134 +static VOID moveouts _ANSI_ARGS_((struct nfa *, struct state *, struct state *));
   1.135 +static VOID copyouts _ANSI_ARGS_((struct nfa *, struct state *, struct state *));
   1.136 +static VOID cloneouts _ANSI_ARGS_((struct nfa *, struct state *, struct state *, struct state *, int));
   1.137 +static VOID delsub _ANSI_ARGS_((struct nfa *, struct state *, struct state *));
   1.138 +static VOID deltraverse _ANSI_ARGS_((struct nfa *, struct state *, struct state *));
   1.139 +static VOID dupnfa _ANSI_ARGS_((struct nfa *, struct state *, struct state *, struct state *, struct state *));
   1.140 +static VOID duptraverse _ANSI_ARGS_((struct nfa *, struct state *, struct state *));
   1.141 +static VOID cleartraverse _ANSI_ARGS_((struct nfa *, struct state *));
   1.142 +static VOID specialcolors _ANSI_ARGS_((struct nfa *));
   1.143 +static long optimize _ANSI_ARGS_((struct nfa *, FILE *));
   1.144 +static VOID pullback _ANSI_ARGS_((struct nfa *, FILE *));
   1.145 +static int pull _ANSI_ARGS_((struct nfa *, struct arc *));
   1.146 +static VOID pushfwd _ANSI_ARGS_((struct nfa *, FILE *));
   1.147 +static int push _ANSI_ARGS_((struct nfa *, struct arc *));
   1.148 +#define	INCOMPATIBLE	1	/* destroys arc */
   1.149 +#define	SATISFIED	2	/* constraint satisfied */
   1.150 +#define	COMPATIBLE	3	/* compatible but not satisfied yet */
   1.151 +static int combine _ANSI_ARGS_((struct arc *, struct arc *));
   1.152 +static VOID fixempties _ANSI_ARGS_((struct nfa *, FILE *));
   1.153 +static int unempty _ANSI_ARGS_((struct nfa *, struct arc *));
   1.154 +static VOID cleanup _ANSI_ARGS_((struct nfa *));
   1.155 +static VOID markreachable _ANSI_ARGS_((struct nfa *, struct state *, struct state *, struct state *));
   1.156 +static VOID markcanreach _ANSI_ARGS_((struct nfa *, struct state *, struct state *, struct state *));
   1.157 +static long analyze _ANSI_ARGS_((struct nfa *));
   1.158 +static VOID compact _ANSI_ARGS_((struct nfa *, struct cnfa *));
   1.159 +static VOID carcsort _ANSI_ARGS_((struct carc *, struct carc *));
   1.160 +static VOID freecnfa _ANSI_ARGS_((struct cnfa *));
   1.161 +static VOID dumpnfa _ANSI_ARGS_((struct nfa *, FILE *));
   1.162 +#ifdef REG_DEBUG
   1.163 +static VOID dumpstate _ANSI_ARGS_((struct state *, FILE *));
   1.164 +static VOID dumparcs _ANSI_ARGS_((struct state *, FILE *));
   1.165 +static int dumprarcs _ANSI_ARGS_((struct arc *, struct state *, FILE *, int));
   1.166 +static VOID dumparc _ANSI_ARGS_((struct arc *, struct state *, FILE *));
   1.167 +#endif
   1.168 +static VOID dumpcnfa _ANSI_ARGS_((struct cnfa *, FILE *));
   1.169 +#ifdef REG_DEBUG
   1.170 +static VOID dumpcstate _ANSI_ARGS_((int, struct carc *, struct cnfa *, FILE *));
   1.171 +#endif
   1.172 +/* === regc_cvec.c === */
   1.173 +static struct cvec *newcvec _ANSI_ARGS_((int, int, int));
   1.174 +static struct cvec *clearcvec _ANSI_ARGS_((struct cvec *));
   1.175 +static VOID addchr _ANSI_ARGS_((struct cvec *, pchr));
   1.176 +static VOID addrange _ANSI_ARGS_((struct cvec *, pchr, pchr));
   1.177 +static VOID addmcce _ANSI_ARGS_((struct cvec *, chr *, chr *));
   1.178 +static int haschr _ANSI_ARGS_((struct cvec *, pchr));
   1.179 +static struct cvec *getcvec _ANSI_ARGS_((struct vars *, int, int, int));
   1.180 +static VOID freecvec _ANSI_ARGS_((struct cvec *));
   1.181 +/* === regc_locale.c === */
   1.182 +static int nmcces _ANSI_ARGS_((struct vars *));
   1.183 +static int nleaders _ANSI_ARGS_((struct vars *));
   1.184 +static struct cvec *allmcces _ANSI_ARGS_((struct vars *, struct cvec *));
   1.185 +static celt element _ANSI_ARGS_((struct vars *, chr *, chr *));
   1.186 +static struct cvec *range _ANSI_ARGS_((struct vars *, celt, celt, int));
   1.187 +static int before _ANSI_ARGS_((celt, celt));
   1.188 +static struct cvec *eclass _ANSI_ARGS_((struct vars *, celt, int));
   1.189 +static struct cvec *cclass _ANSI_ARGS_((struct vars *, chr *, chr *, int));
   1.190 +static struct cvec *allcases _ANSI_ARGS_((struct vars *, pchr));
   1.191 +static int cmp _ANSI_ARGS_((CONST chr *, CONST chr *, size_t));
   1.192 +static int casecmp _ANSI_ARGS_((CONST chr *, CONST chr *, size_t));
   1.193 +/* automatically gathered by fwd; do not hand-edit */
   1.194 +/* =====^!^===== end forwards =====^!^===== */
   1.195 +
   1.196 +
   1.197 +
   1.198 +/* internal variables, bundled for easy passing around */
   1.199 +struct vars {
   1.200 +	regex_t *re;
   1.201 +	chr *now;		/* scan pointer into string */
   1.202 +	chr *stop;		/* end of string */
   1.203 +	chr *savenow;		/* saved now and stop for "subroutine call" */
   1.204 +	chr *savestop;
   1.205 +	int err;		/* error code (0 if none) */
   1.206 +	int cflags;		/* copy of compile flags */
   1.207 +	int lasttype;		/* type of previous token */
   1.208 +	int nexttype;		/* type of next token */
   1.209 +	chr nextvalue;		/* value (if any) of next token */
   1.210 +	int lexcon;		/* lexical context type (see lex.c) */
   1.211 +	int nsubexp;		/* subexpression count */
   1.212 +	struct subre **subs;	/* subRE pointer vector */
   1.213 +	size_t nsubs;		/* length of vector */
   1.214 +	struct subre *sub10[10];	/* initial vector, enough for most */
   1.215 +	struct nfa *nfa;	/* the NFA */
   1.216 +	struct colormap *cm;	/* character color map */
   1.217 +	color nlcolor;		/* color of newline */
   1.218 +	struct state *wordchrs;	/* state in nfa holding word-char outarcs */
   1.219 +	struct subre *tree;	/* subexpression tree */
   1.220 +	struct subre *treechain;	/* all tree nodes allocated */
   1.221 +	struct subre *treefree;		/* any free tree nodes */
   1.222 +	int ntree;		/* number of tree nodes */
   1.223 +	struct cvec *cv;	/* interface cvec */
   1.224 +	struct cvec *cv2;	/* utility cvec */
   1.225 +	struct cvec *mcces;	/* collating-element information */
   1.226 +#		define	ISCELEADER(v,c)	(v->mcces != NULL && haschr(v->mcces, (c)))
   1.227 +	struct state *mccepbegin;	/* in nfa, start of MCCE prototypes */
   1.228 +	struct state *mccepend;	/* in nfa, end of MCCE prototypes */
   1.229 +	struct subre *lacons;	/* lookahead-constraint vector */
   1.230 +	int nlacons;		/* size of lacons */
   1.231 +};
   1.232 +
   1.233 +/* parsing macros; most know that `v' is the struct vars pointer */
   1.234 +#define	NEXT()	(next(v))		/* advance by one token */
   1.235 +#define	SEE(t)	(v->nexttype == (t))	/* is next token this? */
   1.236 +#define	EAT(t)	(SEE(t) && next(v))	/* if next is this, swallow it */
   1.237 +#define	VISERR(vv)	((vv)->err != 0)	/* have we seen an error yet? */
   1.238 +#define	ISERR()	VISERR(v)
   1.239 +#define	VERR(vv,e)	((vv)->nexttype = EOS, ((vv)->err) ? (vv)->err :\
   1.240 +							((vv)->err = (e)))
   1.241 +#define	ERR(e)	VERR(v, e)		/* record an error */
   1.242 +#define	NOERR()	{if (ISERR()) return;}	/* if error seen, return */
   1.243 +#define	NOERRN()	{if (ISERR()) return NULL;}	/* NOERR with retval */
   1.244 +#define	NOERRZ()	{if (ISERR()) return 0;}	/* NOERR with retval */
   1.245 +#define	INSIST(c, e)	((c) ? 0 : ERR(e))	/* if condition false, error */
   1.246 +#define	NOTE(b)	(v->re->re_info |= (b))		/* note visible condition */
   1.247 +#define	EMPTYARC(x, y)	newarc(v->nfa, EMPTY, 0, x, y)
   1.248 +
   1.249 +/* token type codes, some also used as NFA arc types */
   1.250 +#define	EMPTY	'n'		/* no token present */
   1.251 +#define	EOS	'e'		/* end of string */
   1.252 +#define	PLAIN	'p'		/* ordinary character */
   1.253 +#define	DIGIT	'd'		/* digit (in bound) */
   1.254 +#define	BACKREF	'b'		/* back reference */
   1.255 +#define	COLLEL	'I'		/* start of [. */
   1.256 +#define	ECLASS	'E'		/* start of [= */
   1.257 +#define	CCLASS	'C'		/* start of [: */
   1.258 +#define	END	'X'		/* end of [. [= [: */
   1.259 +#define	RANGE	'R'		/* - within [] which might be range delim. */
   1.260 +#define	LACON	'L'		/* lookahead constraint subRE */
   1.261 +#define	AHEAD	'a'		/* color-lookahead arc */
   1.262 +#define	BEHIND	'r'		/* color-lookbehind arc */
   1.263 +#define	WBDRY	'w'		/* word boundary constraint */
   1.264 +#define	NWBDRY	'W'		/* non-word-boundary constraint */
   1.265 +#define	SBEGIN	'A'		/* beginning of string (even if not BOL) */
   1.266 +#define	SEND	'Z'		/* end of string (even if not EOL) */
   1.267 +#define	PREFER	'P'		/* length preference */
   1.268 +
   1.269 +/* is an arc colored, and hence on a color chain? */
   1.270 +#define	COLORED(a)	((a)->type == PLAIN || (a)->type == AHEAD || \
   1.271 +							(a)->type == BEHIND)
   1.272 +
   1.273 +
   1.274 +
   1.275 +/* static function list */
   1.276 +static struct fns functions = {
   1.277 +	rfree,			/* regfree insides */
   1.278 +};
   1.279 +
   1.280 +
   1.281 +
   1.282 +/*
   1.283 + - compile - compile regular expression
   1.284 + ^ int compile(regex_t *, CONST chr *, size_t, int);
   1.285 + */
   1.286 +int
   1.287 +compile(re, string, len, flags)
   1.288 +regex_t *re;
   1.289 +CONST chr *string;
   1.290 +size_t len;
   1.291 +int flags;
   1.292 +{
   1.293 +	struct vars var;
   1.294 +	struct vars *v = &var;
   1.295 +	struct guts *g;
   1.296 +	int i;
   1.297 +	size_t j;
   1.298 +	FILE *debug = (flags&REG_PROGRESS) ? stdout : (FILE *)NULL;
   1.299 +#	define	CNOERR()	{ if (ISERR()) return freev(v, v->err); }
   1.300 +
   1.301 +	/* sanity checks */
   1.302 +
   1.303 +	if (re == NULL || string == NULL)
   1.304 +		return REG_INVARG;
   1.305 +	if ((flags&REG_QUOTE) &&
   1.306 +			(flags&(REG_ADVANCED|REG_EXPANDED|REG_NEWLINE)))
   1.307 +		return REG_INVARG;
   1.308 +	if (!(flags&REG_EXTENDED) && (flags&REG_ADVF))
   1.309 +		return REG_INVARG;
   1.310 +
   1.311 +	/* initial setup (after which freev() is callable) */
   1.312 +	v->re = re;
   1.313 +	v->now = (chr *)string;
   1.314 +	v->stop = v->now + len;
   1.315 +	v->savenow = v->savestop = NULL;
   1.316 +	v->err = 0;
   1.317 +	v->cflags = flags;
   1.318 +	v->nsubexp = 0;
   1.319 +	v->subs = v->sub10;
   1.320 +	v->nsubs = 10;
   1.321 +	for (j = 0; j < v->nsubs; j++)
   1.322 +		v->subs[j] = NULL;
   1.323 +	v->nfa = NULL;
   1.324 +	v->cm = NULL;
   1.325 +	v->nlcolor = COLORLESS;
   1.326 +	v->wordchrs = NULL;
   1.327 +	v->tree = NULL;
   1.328 +	v->treechain = NULL;
   1.329 +	v->treefree = NULL;
   1.330 +	v->cv = NULL;
   1.331 +	v->cv2 = NULL;
   1.332 +	v->mcces = NULL;
   1.333 +	v->lacons = NULL;
   1.334 +	v->nlacons = 0;
   1.335 +	re->re_magic = REMAGIC;
   1.336 +	re->re_info = 0;		/* bits get set during parse */
   1.337 +	re->re_csize = sizeof(chr);
   1.338 +	re->re_guts = NULL;
   1.339 +	re->re_fns = VS(&functions);
   1.340 +
   1.341 +	/* more complex setup, malloced things */
   1.342 +	re->re_guts = VS(MALLOC(sizeof(struct guts)));
   1.343 +	if (re->re_guts == NULL)
   1.344 +		return freev(v, REG_ESPACE);
   1.345 +	g = (struct guts *)re->re_guts;
   1.346 +	g->tree = NULL;
   1.347 +	initcm(v, &g->cmap);
   1.348 +	v->cm = &g->cmap;
   1.349 +	g->lacons = NULL;
   1.350 +	g->nlacons = 0;
   1.351 +	ZAPCNFA(g->search);
   1.352 +	v->nfa = newnfa(v, v->cm, (struct nfa *)NULL);
   1.353 +	CNOERR();
   1.354 +	v->cv = newcvec(100, 20, 10);
   1.355 +	if (v->cv == NULL)
   1.356 +		return freev(v, REG_ESPACE);
   1.357 +	i = nmcces(v);
   1.358 +	if (i > 0) {
   1.359 +		v->mcces = newcvec(nleaders(v), 0, i);
   1.360 +		CNOERR();
   1.361 +		v->mcces = allmcces(v, v->mcces);
   1.362 +		leaders(v, v->mcces);
   1.363 +		addmcce(v->mcces, (chr *)NULL, (chr *)NULL);	/* dummy */
   1.364 +	}
   1.365 +	CNOERR();
   1.366 +
   1.367 +	/* parsing */
   1.368 +	lexstart(v);			/* also handles prefixes */
   1.369 +	if ((v->cflags&REG_NLSTOP) || (v->cflags&REG_NLANCH)) {
   1.370 +		/* assign newline a unique color */
   1.371 +		v->nlcolor = subcolor(v->cm, newline());
   1.372 +		okcolors(v->nfa, v->cm);
   1.373 +	}
   1.374 +	CNOERR();
   1.375 +	v->tree = parse(v, EOS, PLAIN, v->nfa->init, v->nfa->final);
   1.376 +	assert(SEE(EOS));		/* even if error; ISERR() => SEE(EOS) */
   1.377 +	CNOERR();
   1.378 +	assert(v->tree != NULL);
   1.379 +
   1.380 +	/* finish setup of nfa and its subre tree */
   1.381 +	specialcolors(v->nfa);
   1.382 +	CNOERR();
   1.383 +	if (debug != NULL) {
   1.384 +		fprintf(debug, "\n\n\n========= RAW ==========\n");
   1.385 +		dumpnfa(v->nfa, debug);
   1.386 +		dumpst(v->tree, debug, 1);
   1.387 +	}
   1.388 +	optst(v, v->tree);
   1.389 +	v->ntree = numst(v->tree, 1);
   1.390 +	markst(v->tree);
   1.391 +	cleanst(v);
   1.392 +	if (debug != NULL) {
   1.393 +		fprintf(debug, "\n\n\n========= TREE FIXED ==========\n");
   1.394 +		dumpst(v->tree, debug, 1);
   1.395 +	}
   1.396 +
   1.397 +	/* build compacted NFAs for tree and lacons */
   1.398 +	re->re_info |= nfatree(v, v->tree, debug);
   1.399 +	CNOERR();
   1.400 +	assert(v->nlacons == 0 || v->lacons != NULL);
   1.401 +	for (i = 1; i < v->nlacons; i++) {
   1.402 +		if (debug != NULL)
   1.403 +			fprintf(debug, "\n\n\n========= LA%d ==========\n", i);
   1.404 +		nfanode(v, &v->lacons[i], debug);
   1.405 +	}
   1.406 +	CNOERR();
   1.407 +	if (v->tree->flags&SHORTER)
   1.408 +		NOTE(REG_USHORTEST);
   1.409 +
   1.410 +	/* build compacted NFAs for tree, lacons, fast search */
   1.411 +	if (debug != NULL)
   1.412 +		fprintf(debug, "\n\n\n========= SEARCH ==========\n");
   1.413 +	/* can sacrifice main NFA now, so use it as work area */
   1.414 +	(DISCARD)optimize(v->nfa, debug);
   1.415 +	CNOERR();
   1.416 +	makesearch(v, v->nfa);
   1.417 +	CNOERR();
   1.418 +	compact(v->nfa, &g->search);
   1.419 +	CNOERR();
   1.420 +
   1.421 +	/* looks okay, package it up */
   1.422 +	re->re_nsub = v->nsubexp;
   1.423 +	v->re = NULL;			/* freev no longer frees re */
   1.424 +	g->magic = GUTSMAGIC;
   1.425 +	g->cflags = v->cflags;
   1.426 +	g->info = re->re_info;
   1.427 +	g->nsub = re->re_nsub;
   1.428 +	g->tree = v->tree;
   1.429 +	v->tree = NULL;
   1.430 +	g->ntree = v->ntree;
   1.431 +	g->compare = (v->cflags&REG_ICASE) ? casecmp : cmp;
   1.432 +	g->lacons = v->lacons;
   1.433 +	v->lacons = NULL;
   1.434 +	g->nlacons = v->nlacons;
   1.435 +
   1.436 +	if (flags&REG_DUMP)
   1.437 +		dump(re, stdout);
   1.438 +
   1.439 +	assert(v->err == 0);
   1.440 +	return freev(v, 0);
   1.441 +}
   1.442 +
   1.443 +/*
   1.444 + - moresubs - enlarge subRE vector
   1.445 + ^ static VOID moresubs(struct vars *, int);
   1.446 + */
   1.447 +static VOID
   1.448 +moresubs(v, wanted)
   1.449 +struct vars *v;
   1.450 +int wanted;			/* want enough room for this one */
   1.451 +{
   1.452 +	struct subre **p;
   1.453 +	size_t n;
   1.454 +
   1.455 +	assert(wanted > 0 && (size_t)wanted >= v->nsubs);
   1.456 +	n = (size_t)wanted * 3 / 2 + 1;
   1.457 +	if (v->subs == v->sub10) {
   1.458 +		p = (struct subre **)MALLOC(n * sizeof(struct subre *));
   1.459 +		if (p != NULL)
   1.460 +			memcpy(VS(p), VS(v->subs),
   1.461 +					v->nsubs * sizeof(struct subre *));
   1.462 +	} else
   1.463 +		p = (struct subre **)REALLOC(v->subs, n*sizeof(struct subre *));
   1.464 +	if (p == NULL) {
   1.465 +		ERR(REG_ESPACE);
   1.466 +		return;
   1.467 +	}
   1.468 +	v->subs = p;
   1.469 +	for (p = &v->subs[v->nsubs]; v->nsubs < n; p++, v->nsubs++)
   1.470 +		*p = NULL;
   1.471 +	assert(v->nsubs == n);
   1.472 +	assert((size_t)wanted < v->nsubs);
   1.473 +}
   1.474 +
   1.475 +/*
   1.476 + - freev - free vars struct's substructures where necessary
   1.477 + * Optionally does error-number setting, and always returns error code
   1.478 + * (if any), to make error-handling code terser.
   1.479 + ^ static int freev(struct vars *, int);
   1.480 + */
   1.481 +static int
   1.482 +freev(v, err)
   1.483 +struct vars *v;
   1.484 +int err;
   1.485 +{
   1.486 +	if (v->re != NULL)
   1.487 +		rfree(v->re);
   1.488 +	if (v->subs != v->sub10)
   1.489 +		FREE(v->subs);
   1.490 +	if (v->nfa != NULL)
   1.491 +		freenfa(v->nfa);
   1.492 +	if (v->tree != NULL)
   1.493 +		freesubre(v, v->tree);
   1.494 +	if (v->treechain != NULL)
   1.495 +		cleanst(v);
   1.496 +	if (v->cv != NULL)
   1.497 +		freecvec(v->cv);
   1.498 +	if (v->cv2 != NULL)
   1.499 +		freecvec(v->cv2);
   1.500 +	if (v->mcces != NULL)
   1.501 +		freecvec(v->mcces);
   1.502 +	if (v->lacons != NULL)
   1.503 +		freelacons(v->lacons, v->nlacons);
   1.504 +	ERR(err);			/* nop if err==0 */
   1.505 +
   1.506 +	return v->err;
   1.507 +}
   1.508 +
   1.509 +/*
   1.510 + - makesearch - turn an NFA into a search NFA (implicit prepend of .*?)
   1.511 + * NFA must have been optimize()d already.
   1.512 + ^ static VOID makesearch(struct vars *, struct nfa *);
   1.513 + */
   1.514 +static VOID
   1.515 +makesearch(v, nfa)
   1.516 +struct vars *v;
   1.517 +struct nfa *nfa;
   1.518 +{
   1.519 +	struct arc *a;
   1.520 +	struct arc *b;
   1.521 +	struct state *pre = nfa->pre;
   1.522 +	struct state *s;
   1.523 +	struct state *s2;
   1.524 +	struct state *slist;
   1.525 +
   1.526 +	/* no loops are needed if it's anchored */
   1.527 +	for (a = pre->outs; a != NULL; a = a->outchain) {
   1.528 +		assert(a->type == PLAIN);
   1.529 +		if (a->co != nfa->bos[0] && a->co != nfa->bos[1])
   1.530 +			break;
   1.531 +	}
   1.532 +	if (a != NULL) {
   1.533 +		/* add implicit .* in front */
   1.534 +		rainbow(nfa, v->cm, PLAIN, COLORLESS, pre, pre);
   1.535 +
   1.536 +		/* and ^* and \A* too -- not always necessary, but harmless */
   1.537 +		newarc(nfa, PLAIN, nfa->bos[0], pre, pre);
   1.538 +		newarc(nfa, PLAIN, nfa->bos[1], pre, pre);
   1.539 +	}
   1.540 +
   1.541 +	/*
   1.542 +	 * Now here's the subtle part.  Because many REs have no lookback
   1.543 +	 * constraints, often knowing when you were in the pre state tells
   1.544 +	 * you little; it's the next state(s) that are informative.  But
   1.545 +	 * some of them may have other inarcs, i.e. it may be possible to
   1.546 +	 * make actual progress and then return to one of them.  We must
   1.547 +	 * de-optimize such cases, splitting each such state into progress
   1.548 +	 * and no-progress states.
   1.549 +	 */
   1.550 +
   1.551 +	/* first, make a list of the states */
   1.552 +	slist = NULL;
   1.553 +	for (a = pre->outs; a != NULL; a = a->outchain) {
   1.554 +		s = a->to;
   1.555 +		for (b = s->ins; b != NULL; b = b->inchain)
   1.556 +			if (b->from != pre)
   1.557 +				break;
   1.558 +		if (b != NULL) {		/* must be split */
   1.559 +			if (s->tmp == NULL) {  /* if not already in the list */
   1.560 +			                       /* (fixes bugs 505048, 230589, */
   1.561 +			                       /* 840258, 504785) */
   1.562 +				s->tmp = slist;
   1.563 +				slist = s;
   1.564 +			}
   1.565 +		}
   1.566 +	}
   1.567 +
   1.568 +	/* do the splits */
   1.569 +	for (s = slist; s != NULL; s = s2) {
   1.570 +		s2 = newstate(nfa);
   1.571 +		copyouts(nfa, s, s2);
   1.572 +		for (a = s->ins; a != NULL; a = b) {
   1.573 +			b = a->inchain;
   1.574 +			if (a->from != pre) {
   1.575 +				cparc(nfa, a, a->from, s2);
   1.576 +				freearc(nfa, a);
   1.577 +			}
   1.578 +		}
   1.579 +		s2 = s->tmp;
   1.580 +		s->tmp = NULL;		/* clean up while we're at it */
   1.581 +	}
   1.582 +}
   1.583 +
   1.584 +/*
   1.585 + - parse - parse an RE
   1.586 + * This is actually just the top level, which parses a bunch of branches
   1.587 + * tied together with '|'.  They appear in the tree as the left children
   1.588 + * of a chain of '|' subres.
   1.589 + ^ static struct subre *parse(struct vars *, int, int, struct state *,
   1.590 + ^ 	struct state *);
   1.591 + */
   1.592 +static struct subre *
   1.593 +parse(v, stopper, type, init, final)
   1.594 +struct vars *v;
   1.595 +int stopper;			/* EOS or ')' */
   1.596 +int type;			/* LACON (lookahead subRE) or PLAIN */
   1.597 +struct state *init;		/* initial state */
   1.598 +struct state *final;		/* final state */
   1.599 +{
   1.600 +	struct state *left;	/* scaffolding for branch */
   1.601 +	struct state *right;
   1.602 +	struct subre *branches;	/* top level */
   1.603 +	struct subre *branch;	/* current branch */
   1.604 +	struct subre *t;	/* temporary */
   1.605 +	int firstbranch;	/* is this the first branch? */
   1.606 +
   1.607 +	assert(stopper == ')' || stopper == EOS);
   1.608 +
   1.609 +	branches = subre(v, '|', LONGER, init, final);
   1.610 +	NOERRN();
   1.611 +	branch = branches;
   1.612 +	firstbranch = 1;
   1.613 +	do {	/* a branch */
   1.614 +		if (!firstbranch) {
   1.615 +			/* need a place to hang it */
   1.616 +			branch->right = subre(v, '|', LONGER, init, final);
   1.617 +			NOERRN();
   1.618 +			branch = branch->right;
   1.619 +		}
   1.620 +		firstbranch = 0;
   1.621 +		left = newstate(v->nfa);
   1.622 +		right = newstate(v->nfa);
   1.623 +		NOERRN();
   1.624 +		EMPTYARC(init, left);
   1.625 +		EMPTYARC(right, final);
   1.626 +		NOERRN();
   1.627 +		branch->left = parsebranch(v, stopper, type, left, right, 0);
   1.628 +		NOERRN();
   1.629 +		branch->flags |= UP(branch->flags | branch->left->flags);
   1.630 +		if ((branch->flags &~ branches->flags) != 0)	/* new flags */
   1.631 +			for (t = branches; t != branch; t = t->right)
   1.632 +				t->flags |= branch->flags;
   1.633 +	} while (EAT('|'));
   1.634 +	assert(SEE(stopper) || SEE(EOS));
   1.635 +
   1.636 +	if (!SEE(stopper)) {
   1.637 +		assert(stopper == ')' && SEE(EOS));
   1.638 +		ERR(REG_EPAREN);
   1.639 +	}
   1.640 +
   1.641 +	/* optimize out simple cases */
   1.642 +	if (branch == branches) {	/* only one branch */
   1.643 +		assert(branch->right == NULL);
   1.644 +		t = branch->left;
   1.645 +		branch->left = NULL;
   1.646 +		freesubre(v, branches);
   1.647 +		branches = t;
   1.648 +	} else if (!MESSY(branches->flags)) {	/* no interesting innards */
   1.649 +		freesubre(v, branches->left);
   1.650 +		branches->left = NULL;
   1.651 +		freesubre(v, branches->right);
   1.652 +		branches->right = NULL;
   1.653 +		branches->op = '=';
   1.654 +	}
   1.655 +
   1.656 +	return branches;
   1.657 +}
   1.658 +
   1.659 +/*
   1.660 + - parsebranch - parse one branch of an RE
   1.661 + * This mostly manages concatenation, working closely with parseqatom().
   1.662 + * Concatenated things are bundled up as much as possible, with separate
   1.663 + * ',' nodes introduced only when necessary due to substructure.
   1.664 + ^ static struct subre *parsebranch(struct vars *, int, int, struct state *,
   1.665 + ^ 	struct state *, int);
   1.666 + */
   1.667 +static struct subre *
   1.668 +parsebranch(v, stopper, type, left, right, partial)
   1.669 +struct vars *v;
   1.670 +int stopper;			/* EOS or ')' */
   1.671 +int type;			/* LACON (lookahead subRE) or PLAIN */
   1.672 +struct state *left;		/* leftmost state */
   1.673 +struct state *right;		/* rightmost state */
   1.674 +int partial;			/* is this only part of a branch? */
   1.675 +{
   1.676 +	struct state *lp;	/* left end of current construct */
   1.677 +	int seencontent;	/* is there anything in this branch yet? */
   1.678 +	struct subre *t;
   1.679 +
   1.680 +	lp = left;
   1.681 +	seencontent = 0;
   1.682 +	t = subre(v, '=', 0, left, right);	/* op '=' is tentative */
   1.683 +	NOERRN();
   1.684 +	while (!SEE('|') && !SEE(stopper) && !SEE(EOS)) {
   1.685 +		if (seencontent) {	/* implicit concat operator */
   1.686 +			lp = newstate(v->nfa);
   1.687 +			NOERRN();
   1.688 +			moveins(v->nfa, right, lp);
   1.689 +		}
   1.690 +		seencontent = 1;
   1.691 +
   1.692 +		/* NB, recursion in parseqatom() may swallow rest of branch */
   1.693 +		parseqatom(v, stopper, type, lp, right, t);
   1.694 +	}
   1.695 +
   1.696 +	if (!seencontent) {		/* empty branch */
   1.697 +		if (!partial)
   1.698 +			NOTE(REG_UUNSPEC);
   1.699 +		assert(lp == left);
   1.700 +		EMPTYARC(left, right);
   1.701 +	}
   1.702 +
   1.703 +	return t;
   1.704 +}
   1.705 +
   1.706 +/*
   1.707 + - parseqatom - parse one quantified atom or constraint of an RE
   1.708 + * The bookkeeping near the end cooperates very closely with parsebranch();
   1.709 + * in particular, it contains a recursion that can involve parsing the rest
   1.710 + * of the branch, making this function's name somewhat inaccurate.
   1.711 + ^ static VOID parseqatom(struct vars *, int, int, struct state *,
   1.712 + ^ 	struct state *, struct subre *);
   1.713 + */
   1.714 +static VOID
   1.715 +parseqatom(v, stopper, type, lp, rp, top)
   1.716 +struct vars *v;
   1.717 +int stopper;			/* EOS or ')' */
   1.718 +int type;			/* LACON (lookahead subRE) or PLAIN */
   1.719 +struct state *lp;		/* left state to hang it on */
   1.720 +struct state *rp;		/* right state to hang it on */
   1.721 +struct subre *top;		/* subtree top */
   1.722 +{
   1.723 +	struct state *s;	/* temporaries for new states */
   1.724 +	struct state *s2;
   1.725 +#	define	ARCV(t, val)	newarc(v->nfa, t, val, lp, rp)
   1.726 +	int m, n;
   1.727 +	struct subre *atom;	/* atom's subtree */
   1.728 +	struct subre *t;
   1.729 +	int cap;		/* capturing parens? */
   1.730 +	int pos;		/* positive lookahead? */
   1.731 +	int subno;		/* capturing-parens or backref number */
   1.732 +	int atomtype;
   1.733 +	int qprefer;		/* quantifier short/long preference */
   1.734 +	int f;
   1.735 +	struct subre **atomp;	/* where the pointer to atom is */
   1.736 +
   1.737 +	/* initial bookkeeping */
   1.738 +	atom = NULL;
   1.739 +	assert(lp->nouts == 0);	/* must string new code */
   1.740 +	assert(rp->nins == 0);	/*  between lp and rp */
   1.741 +	subno = 0;		/* just to shut lint up */
   1.742 +
   1.743 +	/* an atom or constraint... */
   1.744 +	atomtype = v->nexttype;
   1.745 +	switch (atomtype) {
   1.746 +	/* first, constraints, which end by returning */
   1.747 +	case '^':
   1.748 +		ARCV('^', 1);
   1.749 +		if (v->cflags&REG_NLANCH)
   1.750 +			ARCV(BEHIND, v->nlcolor);
   1.751 +		NEXT();
   1.752 +		return;
   1.753 +		break;
   1.754 +	case '$':
   1.755 +		ARCV('$', 1);
   1.756 +		if (v->cflags&REG_NLANCH)
   1.757 +			ARCV(AHEAD, v->nlcolor);
   1.758 +		NEXT();
   1.759 +		return;
   1.760 +		break;
   1.761 +	case SBEGIN:
   1.762 +		ARCV('^', 1);	/* BOL */
   1.763 +		ARCV('^', 0);	/* or BOS */
   1.764 +		NEXT();
   1.765 +		return;
   1.766 +		break;
   1.767 +	case SEND:
   1.768 +		ARCV('$', 1);	/* EOL */
   1.769 +		ARCV('$', 0);	/* or EOS */
   1.770 +		NEXT();
   1.771 +		return;
   1.772 +		break;
   1.773 +	case '<':
   1.774 +		wordchrs(v);	/* does NEXT() */
   1.775 +		s = newstate(v->nfa);
   1.776 +		NOERR();
   1.777 +		nonword(v, BEHIND, lp, s);
   1.778 +		word(v, AHEAD, s, rp);
   1.779 +		return;
   1.780 +		break;
   1.781 +	case '>':
   1.782 +		wordchrs(v);	/* does NEXT() */
   1.783 +		s = newstate(v->nfa);
   1.784 +		NOERR();
   1.785 +		word(v, BEHIND, lp, s);
   1.786 +		nonword(v, AHEAD, s, rp);
   1.787 +		return;
   1.788 +		break;
   1.789 +	case WBDRY:
   1.790 +		wordchrs(v);	/* does NEXT() */
   1.791 +		s = newstate(v->nfa);
   1.792 +		NOERR();
   1.793 +		nonword(v, BEHIND, lp, s);
   1.794 +		word(v, AHEAD, s, rp);
   1.795 +		s = newstate(v->nfa);
   1.796 +		NOERR();
   1.797 +		word(v, BEHIND, lp, s);
   1.798 +		nonword(v, AHEAD, s, rp);
   1.799 +		return;
   1.800 +		break;
   1.801 +	case NWBDRY:
   1.802 +		wordchrs(v);	/* does NEXT() */
   1.803 +		s = newstate(v->nfa);
   1.804 +		NOERR();
   1.805 +		word(v, BEHIND, lp, s);
   1.806 +		word(v, AHEAD, s, rp);
   1.807 +		s = newstate(v->nfa);
   1.808 +		NOERR();
   1.809 +		nonword(v, BEHIND, lp, s);
   1.810 +		nonword(v, AHEAD, s, rp);
   1.811 +		return;
   1.812 +		break;
   1.813 +	case LACON:	/* lookahead constraint */
   1.814 +		pos = v->nextvalue;
   1.815 +		NEXT();
   1.816 +		s = newstate(v->nfa);
   1.817 +		s2 = newstate(v->nfa);
   1.818 +		NOERR();
   1.819 +		t = parse(v, ')', LACON, s, s2);
   1.820 +		freesubre(v, t);	/* internal structure irrelevant */
   1.821 +		assert(SEE(')') || ISERR());
   1.822 +		NEXT();
   1.823 +		n = newlacon(v, s, s2, pos);
   1.824 +		NOERR();
   1.825 +		ARCV(LACON, n);
   1.826 +		return;
   1.827 +		break;
   1.828 +	/* then errors, to get them out of the way */
   1.829 +	case '*':
   1.830 +	case '+':
   1.831 +	case '?':
   1.832 +	case '{':
   1.833 +		ERR(REG_BADRPT);
   1.834 +		return;
   1.835 +		break;
   1.836 +	default:
   1.837 +		ERR(REG_ASSERT);
   1.838 +		return;
   1.839 +		break;
   1.840 +	/* then plain characters, and minor variants on that theme */
   1.841 +	case ')':		/* unbalanced paren */
   1.842 +		if ((v->cflags&REG_ADVANCED) != REG_EXTENDED) {
   1.843 +			ERR(REG_EPAREN);
   1.844 +			return;
   1.845 +		}
   1.846 +		/* legal in EREs due to specification botch */
   1.847 +		NOTE(REG_UPBOTCH);
   1.848 +		/* fallthrough into case PLAIN */
   1.849 +	case PLAIN:
   1.850 +		onechr(v, v->nextvalue, lp, rp);
   1.851 +		okcolors(v->nfa, v->cm);
   1.852 +		NOERR();
   1.853 +		NEXT();
   1.854 +		break;
   1.855 +	case '[':
   1.856 +		if (v->nextvalue == 1)
   1.857 +			bracket(v, lp, rp);
   1.858 +		else
   1.859 +			cbracket(v, lp, rp);
   1.860 +		assert(SEE(']') || ISERR());
   1.861 +		NEXT();
   1.862 +		break;
   1.863 +	case '.':
   1.864 +		rainbow(v->nfa, v->cm, PLAIN,
   1.865 +				(v->cflags&REG_NLSTOP) ? v->nlcolor : COLORLESS,
   1.866 +				lp, rp);
   1.867 +		NEXT();
   1.868 +		break;
   1.869 +	/* and finally the ugly stuff */
   1.870 +	case '(':	/* value flags as capturing or non */
   1.871 +		cap = (type == LACON) ? 0 : v->nextvalue;
   1.872 +		if (cap) {
   1.873 +			v->nsubexp++;
   1.874 +			subno = v->nsubexp;
   1.875 +			if ((size_t)subno >= v->nsubs)
   1.876 +				moresubs(v, subno);
   1.877 +			assert((size_t)subno < v->nsubs);
   1.878 +		} else
   1.879 +			atomtype = PLAIN;	/* something that's not '(' */
   1.880 +		NEXT();
   1.881 +		/* need new endpoints because tree will contain pointers */
   1.882 +		s = newstate(v->nfa);
   1.883 +		s2 = newstate(v->nfa);
   1.884 +		NOERR();
   1.885 +		EMPTYARC(lp, s);
   1.886 +		EMPTYARC(s2, rp);
   1.887 +		NOERR();
   1.888 +		atom = parse(v, ')', PLAIN, s, s2);
   1.889 +		assert(SEE(')') || ISERR());
   1.890 +		NEXT();
   1.891 +		NOERR();
   1.892 +		if (cap) {
   1.893 +			v->subs[subno] = atom;
   1.894 +			t = subre(v, '(', atom->flags|CAP, lp, rp);
   1.895 +			NOERR();
   1.896 +			t->subno = subno;
   1.897 +			t->left = atom;
   1.898 +			atom = t;
   1.899 +		}
   1.900 +		/* postpone everything else pending possible {0} */
   1.901 +		break;
   1.902 +	case BACKREF:	/* the Feature From The Black Lagoon */
   1.903 +		INSIST(type != LACON, REG_ESUBREG);
   1.904 +		INSIST(v->nextvalue < v->nsubs, REG_ESUBREG);
   1.905 +		INSIST(v->subs[v->nextvalue] != NULL, REG_ESUBREG);
   1.906 +		NOERR();
   1.907 +		assert(v->nextvalue > 0);
   1.908 +		atom = subre(v, 'b', BACKR, lp, rp);
   1.909 +		subno = v->nextvalue;
   1.910 +		atom->subno = subno;
   1.911 +		EMPTYARC(lp, rp);	/* temporarily, so there's something */
   1.912 +		NEXT();
   1.913 +		break;
   1.914 +	}
   1.915 +
   1.916 +	/* ...and an atom may be followed by a quantifier */
   1.917 +	switch (v->nexttype) {
   1.918 +	case '*':
   1.919 +		m = 0;
   1.920 +		n = INFINITY;
   1.921 +		qprefer = (v->nextvalue) ? LONGER : SHORTER;
   1.922 +		NEXT();
   1.923 +		break;
   1.924 +	case '+':
   1.925 +		m = 1;
   1.926 +		n = INFINITY;
   1.927 +		qprefer = (v->nextvalue) ? LONGER : SHORTER;
   1.928 +		NEXT();
   1.929 +		break;
   1.930 +	case '?':
   1.931 +		m = 0;
   1.932 +		n = 1;
   1.933 +		qprefer = (v->nextvalue) ? LONGER : SHORTER;
   1.934 +		NEXT();
   1.935 +		break;
   1.936 +	case '{':
   1.937 +		NEXT();
   1.938 +		m = scannum(v);
   1.939 +		if (EAT(',')) {
   1.940 +			if (SEE(DIGIT))
   1.941 +				n = scannum(v);
   1.942 +			else
   1.943 +				n = INFINITY;
   1.944 +			if (m > n) {
   1.945 +				ERR(REG_BADBR);
   1.946 +				return;
   1.947 +			}
   1.948 +			/* {m,n} exercises preference, even if it's {m,m} */
   1.949 +			qprefer = (v->nextvalue) ? LONGER : SHORTER;
   1.950 +		} else {
   1.951 +			n = m;
   1.952 +			/* {m} passes operand's preference through */
   1.953 +			qprefer = 0;
   1.954 +		}
   1.955 +		if (!SEE('}')) {	/* catches errors too */
   1.956 +			ERR(REG_BADBR);
   1.957 +			return;
   1.958 +		}
   1.959 +		NEXT();
   1.960 +		break;
   1.961 +	default:		/* no quantifier */
   1.962 +		m = n = 1;
   1.963 +		qprefer = 0;
   1.964 +		break;
   1.965 +	}
   1.966 +
   1.967 +	/* annoying special case:  {0} or {0,0} cancels everything */
   1.968 +	if (m == 0 && n == 0) {
   1.969 +		if (atom != NULL)
   1.970 +			freesubre(v, atom);
   1.971 +		if (atomtype == '(')
   1.972 +			v->subs[subno] = NULL;
   1.973 +		delsub(v->nfa, lp, rp);
   1.974 +		EMPTYARC(lp, rp);
   1.975 +		return;
   1.976 +	}
   1.977 +
   1.978 +	/* if not a messy case, avoid hard part */
   1.979 +	assert(!MESSY(top->flags));
   1.980 +	f = top->flags | qprefer | ((atom != NULL) ? atom->flags : 0);
   1.981 +	if (atomtype != '(' && atomtype != BACKREF && !MESSY(UP(f))) {
   1.982 +		if (!(m == 1 && n == 1))
   1.983 +			repeat(v, lp, rp, m, n);
   1.984 +		if (atom != NULL)
   1.985 +			freesubre(v, atom);
   1.986 +		top->flags = f;
   1.987 +		return;
   1.988 +	}
   1.989 +
   1.990 +	/*
   1.991 +	 * hard part:  something messy
   1.992 +	 * That is, capturing parens, back reference, short/long clash, or
   1.993 +	 * an atom with substructure containing one of those.
   1.994 +	 */
   1.995 +
   1.996 +	/* now we'll need a subre for the contents even if they're boring */
   1.997 +	if (atom == NULL) {
   1.998 +		atom = subre(v, '=', 0, lp, rp);
   1.999 +		NOERR();
  1.1000 +	}
  1.1001 +
  1.1002 +	/*
  1.1003 +	 * prepare a general-purpose state skeleton
  1.1004 +	 *
  1.1005 +	 *    ---> [s] ---prefix---> [begin] ---atom---> [end] ----rest---> [rp]
  1.1006 +	 *   /                                            /
  1.1007 +	 * [lp] ----> [s2] ----bypass---------------------
  1.1008 +	 *
  1.1009 +	 * where bypass is an empty, and prefix is some repetitions of atom
  1.1010 +	 */
  1.1011 +	s = newstate(v->nfa);		/* first, new endpoints for the atom */
  1.1012 +	s2 = newstate(v->nfa);
  1.1013 +	NOERR();
  1.1014 +	moveouts(v->nfa, lp, s);
  1.1015 +	moveins(v->nfa, rp, s2);
  1.1016 +	NOERR();
  1.1017 +	atom->begin = s;
  1.1018 +	atom->end = s2;
  1.1019 +	s = newstate(v->nfa);		/* and spots for prefix and bypass */
  1.1020 +	s2 = newstate(v->nfa);
  1.1021 +	NOERR();
  1.1022 +	EMPTYARC(lp, s);
  1.1023 +	EMPTYARC(lp, s2);
  1.1024 +	NOERR();
  1.1025 +
  1.1026 +	/* break remaining subRE into x{...} and what follows */
  1.1027 +	t = subre(v, '.', COMBINE(qprefer, atom->flags), lp, rp);
  1.1028 +	t->left = atom;
  1.1029 +	atomp = &t->left;
  1.1030 +	/* here we should recurse... but we must postpone that to the end */
  1.1031 +
  1.1032 +	/* split top into prefix and remaining */
  1.1033 +	assert(top->op == '=' && top->left == NULL && top->right == NULL);
  1.1034 +	top->left = subre(v, '=', top->flags, top->begin, lp);
  1.1035 +	top->op = '.';
  1.1036 +	top->right = t;
  1.1037 +
  1.1038 +	/* if it's a backref, now is the time to replicate the subNFA */
  1.1039 +	if (atomtype == BACKREF) {
  1.1040 +		assert(atom->begin->nouts == 1);	/* just the EMPTY */
  1.1041 +		delsub(v->nfa, atom->begin, atom->end);
  1.1042 +		assert(v->subs[subno] != NULL);
  1.1043 +		/* and here's why the recursion got postponed:  it must */
  1.1044 +		/* wait until the skeleton is filled in, because it may */
  1.1045 +		/* hit a backref that wants to copy the filled-in skeleton */
  1.1046 +		dupnfa(v->nfa, v->subs[subno]->begin, v->subs[subno]->end,
  1.1047 +						atom->begin, atom->end);
  1.1048 +		NOERR();
  1.1049 +	}
  1.1050 +
  1.1051 +	/* it's quantifier time; first, turn x{0,...} into x{1,...}|empty */
  1.1052 +	if (m == 0) {
  1.1053 +		EMPTYARC(s2, atom->end);		/* the bypass */
  1.1054 +		assert(PREF(qprefer) != 0);
  1.1055 +		f = COMBINE(qprefer, atom->flags);
  1.1056 +		t = subre(v, '|', f, lp, atom->end);
  1.1057 +		NOERR();
  1.1058 +		t->left = atom;
  1.1059 +		t->right = subre(v, '|', PREF(f), s2, atom->end);
  1.1060 +		NOERR();
  1.1061 +		t->right->left = subre(v, '=', 0, s2, atom->end);
  1.1062 +		NOERR();
  1.1063 +		*atomp = t;
  1.1064 +		atomp = &t->left;
  1.1065 +		m = 1;
  1.1066 +	}
  1.1067 +
  1.1068 +	/* deal with the rest of the quantifier */
  1.1069 +	if (atomtype == BACKREF) {
  1.1070 +		/* special case:  backrefs have internal quantifiers */
  1.1071 +		EMPTYARC(s, atom->begin);	/* empty prefix */
  1.1072 +		/* just stuff everything into atom */
  1.1073 +		repeat(v, atom->begin, atom->end, m, n);
  1.1074 +		atom->min = (short)m;
  1.1075 +		atom->max = (short)n;
  1.1076 +		atom->flags |= COMBINE(qprefer, atom->flags);
  1.1077 +	} else if (m == 1 && n == 1) {
  1.1078 +		/* no/vacuous quantifier:  done */
  1.1079 +		EMPTYARC(s, atom->begin);	/* empty prefix */
  1.1080 +	} else {
  1.1081 +		/* turn x{m,n} into x{m-1,n-1}x, with capturing */
  1.1082 +		/*  parens in only second x */
  1.1083 +		dupnfa(v->nfa, atom->begin, atom->end, s, atom->begin);
  1.1084 +		assert(m >= 1 && m != INFINITY && n >= 1);
  1.1085 +		repeat(v, s, atom->begin, m-1, (n == INFINITY) ? n : n-1);
  1.1086 +		f = COMBINE(qprefer, atom->flags);
  1.1087 +		t = subre(v, '.', f, s, atom->end);	/* prefix and atom */
  1.1088 +		NOERR();
  1.1089 +		t->left = subre(v, '=', PREF(f), s, atom->begin);
  1.1090 +		NOERR();
  1.1091 +		t->right = atom;
  1.1092 +		*atomp = t;
  1.1093 +	}
  1.1094 +
  1.1095 +	/* and finally, look after that postponed recursion */
  1.1096 +	t = top->right;
  1.1097 +	if (!(SEE('|') || SEE(stopper) || SEE(EOS)))
  1.1098 +		t->right = parsebranch(v, stopper, type, atom->end, rp, 1);
  1.1099 +	else {
  1.1100 +		EMPTYARC(atom->end, rp);
  1.1101 +		t->right = subre(v, '=', 0, atom->end, rp);
  1.1102 +	}
  1.1103 +	assert(SEE('|') || SEE(stopper) || SEE(EOS));
  1.1104 +	t->flags |= COMBINE(t->flags, t->right->flags);
  1.1105 +	top->flags |= COMBINE(top->flags, t->flags);
  1.1106 +}
  1.1107 +
  1.1108 +/*
  1.1109 + - nonword - generate arcs for non-word-character ahead or behind
  1.1110 + ^ static VOID nonword(struct vars *, int, struct state *, struct state *);
  1.1111 + */
  1.1112 +static VOID
  1.1113 +nonword(v, dir, lp, rp)
  1.1114 +struct vars *v;
  1.1115 +int dir;			/* AHEAD or BEHIND */
  1.1116 +struct state *lp;
  1.1117 +struct state *rp;
  1.1118 +{
  1.1119 +	int anchor = (dir == AHEAD) ? '$' : '^';
  1.1120 +
  1.1121 +	assert(dir == AHEAD || dir == BEHIND);
  1.1122 +	newarc(v->nfa, anchor, 1, lp, rp);
  1.1123 +	newarc(v->nfa, anchor, 0, lp, rp);
  1.1124 +	colorcomplement(v->nfa, v->cm, dir, v->wordchrs, lp, rp);
  1.1125 +	/* (no need for special attention to \n) */
  1.1126 +}
  1.1127 +
  1.1128 +/*
  1.1129 + - word - generate arcs for word character ahead or behind
  1.1130 + ^ static VOID word(struct vars *, int, struct state *, struct state *);
  1.1131 + */
  1.1132 +static VOID
  1.1133 +word(v, dir, lp, rp)
  1.1134 +struct vars *v;
  1.1135 +int dir;			/* AHEAD or BEHIND */
  1.1136 +struct state *lp;
  1.1137 +struct state *rp;
  1.1138 +{
  1.1139 +	assert(dir == AHEAD || dir == BEHIND);
  1.1140 +	cloneouts(v->nfa, v->wordchrs, lp, rp, dir);
  1.1141 +	/* (no need for special attention to \n) */
  1.1142 +}
  1.1143 +
  1.1144 +/*
  1.1145 + - scannum - scan a number
  1.1146 + ^ static int scannum(struct vars *);
  1.1147 + */
  1.1148 +static int			/* value, <= DUPMAX */
  1.1149 +scannum(v)
  1.1150 +struct vars *v;
  1.1151 +{
  1.1152 +	int n = 0;
  1.1153 +
  1.1154 +	while (SEE(DIGIT) && n < DUPMAX) {
  1.1155 +		n = n*10 + v->nextvalue;
  1.1156 +		NEXT();
  1.1157 +	}
  1.1158 +	if (SEE(DIGIT) || n > DUPMAX) {
  1.1159 +		ERR(REG_BADBR);
  1.1160 +		return 0;
  1.1161 +	}
  1.1162 +	return n;
  1.1163 +}
  1.1164 +
  1.1165 +/*
  1.1166 + - repeat - replicate subNFA for quantifiers
  1.1167 + * The duplication sequences used here are chosen carefully so that any
  1.1168 + * pointers starting out pointing into the subexpression end up pointing into
  1.1169 + * the last occurrence.  (Note that it may not be strung between the same
  1.1170 + * left and right end states, however!)  This used to be important for the
  1.1171 + * subRE tree, although the important bits are now handled by the in-line
  1.1172 + * code in parse(), and when this is called, it doesn't matter any more.
  1.1173 + ^ static VOID repeat(struct vars *, struct state *, struct state *, int, int);
  1.1174 + */
  1.1175 +static VOID
  1.1176 +repeat(v, lp, rp, m, n)
  1.1177 +struct vars *v;
  1.1178 +struct state *lp;
  1.1179 +struct state *rp;
  1.1180 +int m;
  1.1181 +int n;
  1.1182 +{
  1.1183 +#	define	SOME	2
  1.1184 +#	define	INF	3
  1.1185 +#	define	PAIR(x, y)	((x)*4 + (y))
  1.1186 +#	define	REDUCE(x)	( ((x) == INFINITY) ? INF : (((x) > 1) ? SOME : (x)) )
  1.1187 +	CONST int rm = REDUCE(m);
  1.1188 +	CONST int rn = REDUCE(n);
  1.1189 +	struct state *s;
  1.1190 +	struct state *s2;
  1.1191 +
  1.1192 +	switch (PAIR(rm, rn)) {
  1.1193 +	case PAIR(0, 0):		/* empty string */
  1.1194 +		delsub(v->nfa, lp, rp);
  1.1195 +		EMPTYARC(lp, rp);
  1.1196 +		break;
  1.1197 +	case PAIR(0, 1):		/* do as x| */
  1.1198 +		EMPTYARC(lp, rp);
  1.1199 +		break;
  1.1200 +	case PAIR(0, SOME):		/* do as x{1,n}| */
  1.1201 +		repeat(v, lp, rp, 1, n);
  1.1202 +		NOERR();
  1.1203 +		EMPTYARC(lp, rp);
  1.1204 +		break;
  1.1205 +	case PAIR(0, INF):		/* loop x around */
  1.1206 +		s = newstate(v->nfa);
  1.1207 +		NOERR();
  1.1208 +		moveouts(v->nfa, lp, s);
  1.1209 +		moveins(v->nfa, rp, s);
  1.1210 +		EMPTYARC(lp, s);
  1.1211 +		EMPTYARC(s, rp);
  1.1212 +		break;
  1.1213 +	case PAIR(1, 1):		/* no action required */
  1.1214 +		break;
  1.1215 +	case PAIR(1, SOME):		/* do as x{0,n-1}x = (x{1,n-1}|)x */
  1.1216 +		s = newstate(v->nfa);
  1.1217 +		NOERR();
  1.1218 +		moveouts(v->nfa, lp, s);
  1.1219 +		dupnfa(v->nfa, s, rp, lp, s);
  1.1220 +		NOERR();
  1.1221 +		repeat(v, lp, s, 1, n-1);
  1.1222 +		NOERR();
  1.1223 +		EMPTYARC(lp, s);
  1.1224 +		break;
  1.1225 +	case PAIR(1, INF):		/* add loopback arc */
  1.1226 +		s = newstate(v->nfa);
  1.1227 +		s2 = newstate(v->nfa);
  1.1228 +		NOERR();
  1.1229 +		moveouts(v->nfa, lp, s);
  1.1230 +		moveins(v->nfa, rp, s2);
  1.1231 +		EMPTYARC(lp, s);
  1.1232 +		EMPTYARC(s2, rp);
  1.1233 +		EMPTYARC(s2, s);
  1.1234 +		break;
  1.1235 +	case PAIR(SOME, SOME):		/* do as x{m-1,n-1}x */
  1.1236 +		s = newstate(v->nfa);
  1.1237 +		NOERR();
  1.1238 +		moveouts(v->nfa, lp, s);
  1.1239 +		dupnfa(v->nfa, s, rp, lp, s);
  1.1240 +		NOERR();
  1.1241 +		repeat(v, lp, s, m-1, n-1);
  1.1242 +		break;
  1.1243 +	case PAIR(SOME, INF):		/* do as x{m-1,}x */
  1.1244 +		s = newstate(v->nfa);
  1.1245 +		NOERR();
  1.1246 +		moveouts(v->nfa, lp, s);
  1.1247 +		dupnfa(v->nfa, s, rp, lp, s);
  1.1248 +		NOERR();
  1.1249 +		repeat(v, lp, s, m-1, n);
  1.1250 +		break;
  1.1251 +	default:
  1.1252 +		ERR(REG_ASSERT);
  1.1253 +		break;
  1.1254 +	}
  1.1255 +}
  1.1256 +
  1.1257 +/*
  1.1258 + - bracket - handle non-complemented bracket expression
  1.1259 + * Also called from cbracket for complemented bracket expressions.
  1.1260 + ^ static VOID bracket(struct vars *, struct state *, struct state *);
  1.1261 + */
  1.1262 +static VOID
  1.1263 +bracket(v, lp, rp)
  1.1264 +struct vars *v;
  1.1265 +struct state *lp;
  1.1266 +struct state *rp;
  1.1267 +{
  1.1268 +	assert(SEE('['));
  1.1269 +	NEXT();
  1.1270 +	while (!SEE(']') && !SEE(EOS))
  1.1271 +		brackpart(v, lp, rp);
  1.1272 +	assert(SEE(']') || ISERR());
  1.1273 +	okcolors(v->nfa, v->cm);
  1.1274 +}
  1.1275 +
  1.1276 +/*
  1.1277 + - cbracket - handle complemented bracket expression
  1.1278 + * We do it by calling bracket() with dummy endpoints, and then complementing
  1.1279 + * the result.  The alternative would be to invoke rainbow(), and then delete
  1.1280 + * arcs as the b.e. is seen... but that gets messy.
  1.1281 + ^ static VOID cbracket(struct vars *, struct state *, struct state *);
  1.1282 + */
  1.1283 +static VOID
  1.1284 +cbracket(v, lp, rp)
  1.1285 +struct vars *v;
  1.1286 +struct state *lp;
  1.1287 +struct state *rp;
  1.1288 +{
  1.1289 +	struct state *left = newstate(v->nfa);
  1.1290 +	struct state *right = newstate(v->nfa);
  1.1291 +	struct state *s;
  1.1292 +	struct arc *a;			/* arc from lp */
  1.1293 +	struct arc *ba;			/* arc from left, from bracket() */
  1.1294 +	struct arc *pa;			/* MCCE-prototype arc */
  1.1295 +	color co;
  1.1296 +	chr *p;
  1.1297 +	int i;
  1.1298 +
  1.1299 +	NOERR();
  1.1300 +	bracket(v, left, right);
  1.1301 +	if (v->cflags&REG_NLSTOP)
  1.1302 +		newarc(v->nfa, PLAIN, v->nlcolor, left, right);
  1.1303 +	NOERR();
  1.1304 +
  1.1305 +	assert(lp->nouts == 0);		/* all outarcs will be ours */
  1.1306 +
  1.1307 +	/* easy part of complementing */
  1.1308 +	colorcomplement(v->nfa, v->cm, PLAIN, left, lp, rp);
  1.1309 +	NOERR();
  1.1310 +	if (v->mcces == NULL) {		/* no MCCEs -- we're done */
  1.1311 +		dropstate(v->nfa, left);
  1.1312 +		assert(right->nins == 0);
  1.1313 +		freestate(v->nfa, right);
  1.1314 +		return;
  1.1315 +	}
  1.1316 +
  1.1317 +	/* but complementing gets messy in the presence of MCCEs... */
  1.1318 +	NOTE(REG_ULOCALE);
  1.1319 +	for (p = v->mcces->chrs, i = v->mcces->nchrs; i > 0; p++, i--) {
  1.1320 +		co = GETCOLOR(v->cm, *p);
  1.1321 +		a = findarc(lp, PLAIN, co);
  1.1322 +		ba = findarc(left, PLAIN, co);
  1.1323 +		if (ba == NULL) {
  1.1324 +			assert(a != NULL);
  1.1325 +			freearc(v->nfa, a);
  1.1326 +		} else {
  1.1327 +			assert(a == NULL);
  1.1328 +		}
  1.1329 +		s = newstate(v->nfa);
  1.1330 +		NOERR();
  1.1331 +		newarc(v->nfa, PLAIN, co, lp, s);
  1.1332 +		NOERR();
  1.1333 +		pa = findarc(v->mccepbegin, PLAIN, co);
  1.1334 +		assert(pa != NULL);
  1.1335 +		if (ba == NULL) {	/* easy case, need all of them */
  1.1336 +			cloneouts(v->nfa, pa->to, s, rp, PLAIN);
  1.1337 +			newarc(v->nfa, '$', 1, s, rp);
  1.1338 +			newarc(v->nfa, '$', 0, s, rp);
  1.1339 +			colorcomplement(v->nfa, v->cm, AHEAD, pa->to, s, rp);
  1.1340 +		} else {		/* must be selective */
  1.1341 +			if (findarc(ba->to, '$', 1) == NULL) {
  1.1342 +				newarc(v->nfa, '$', 1, s, rp);
  1.1343 +				newarc(v->nfa, '$', 0, s, rp);
  1.1344 +				colorcomplement(v->nfa, v->cm, AHEAD, pa->to,
  1.1345 +									 s, rp);
  1.1346 +			}
  1.1347 +			for (pa = pa->to->outs; pa != NULL; pa = pa->outchain)
  1.1348 +				if (findarc(ba->to, PLAIN, pa->co) == NULL)
  1.1349 +					newarc(v->nfa, PLAIN, pa->co, s, rp);
  1.1350 +			if (s->nouts == 0)	/* limit of selectivity: none */
  1.1351 +				dropstate(v->nfa, s);	/* frees arc too */
  1.1352 +		}
  1.1353 +		NOERR();
  1.1354 +	}
  1.1355 +
  1.1356 +	delsub(v->nfa, left, right);
  1.1357 +	assert(left->nouts == 0);
  1.1358 +	freestate(v->nfa, left);
  1.1359 +	assert(right->nins == 0);
  1.1360 +	freestate(v->nfa, right);
  1.1361 +}
  1.1362 +			
  1.1363 +/*
  1.1364 + - brackpart - handle one item (or range) within a bracket expression
  1.1365 + ^ static VOID brackpart(struct vars *, struct state *, struct state *);
  1.1366 + */
  1.1367 +static VOID
  1.1368 +brackpart(v, lp, rp)
  1.1369 +struct vars *v;
  1.1370 +struct state *lp;
  1.1371 +struct state *rp;
  1.1372 +{
  1.1373 +	celt startc;
  1.1374 +	celt endc;
  1.1375 +	struct cvec *cv;
  1.1376 +	chr *startp;
  1.1377 +	chr *endp;
  1.1378 +	chr c[1];
  1.1379 +
  1.1380 +	/* parse something, get rid of special cases, take shortcuts */
  1.1381 +	switch (v->nexttype) {
  1.1382 +	case RANGE:			/* a-b-c or other botch */
  1.1383 +		ERR(REG_ERANGE);
  1.1384 +		return;
  1.1385 +		break;
  1.1386 +	case PLAIN:
  1.1387 +		c[0] = v->nextvalue;
  1.1388 +		NEXT();
  1.1389 +		/* shortcut for ordinary chr (not range, not MCCE leader) */
  1.1390 +		if (!SEE(RANGE) && !ISCELEADER(v, c[0])) {
  1.1391 +			onechr(v, c[0], lp, rp);
  1.1392 +			return;
  1.1393 +		}
  1.1394 +		startc = element(v, c, c+1);
  1.1395 +		NOERR();
  1.1396 +		break;
  1.1397 +	case COLLEL:
  1.1398 +		startp = v->now;
  1.1399 +		endp = scanplain(v);
  1.1400 +		INSIST(startp < endp, REG_ECOLLATE);
  1.1401 +		NOERR();
  1.1402 +		startc = element(v, startp, endp);
  1.1403 +		NOERR();
  1.1404 +		break;
  1.1405 +	case ECLASS:
  1.1406 +		startp = v->now;
  1.1407 +		endp = scanplain(v);
  1.1408 +		INSIST(startp < endp, REG_ECOLLATE);
  1.1409 +		NOERR();
  1.1410 +		startc = element(v, startp, endp);
  1.1411 +		NOERR();
  1.1412 +		cv = eclass(v, startc, (v->cflags&REG_ICASE));
  1.1413 +		NOERR();
  1.1414 +		dovec(v, cv, lp, rp);
  1.1415 +		return;
  1.1416 +		break;
  1.1417 +	case CCLASS:
  1.1418 +		startp = v->now;
  1.1419 +		endp = scanplain(v);
  1.1420 +		INSIST(startp < endp, REG_ECTYPE);
  1.1421 +		NOERR();
  1.1422 +		cv = cclass(v, startp, endp, (v->cflags&REG_ICASE));
  1.1423 +		NOERR();
  1.1424 +		dovec(v, cv, lp, rp);
  1.1425 +		return;
  1.1426 +		break;
  1.1427 +	default:
  1.1428 +		ERR(REG_ASSERT);
  1.1429 +		return;
  1.1430 +		break;
  1.1431 +	}
  1.1432 +
  1.1433 +	if (SEE(RANGE)) {
  1.1434 +		NEXT();
  1.1435 +		switch (v->nexttype) {
  1.1436 +		case PLAIN:
  1.1437 +		case RANGE:
  1.1438 +			c[0] = v->nextvalue;
  1.1439 +			NEXT();
  1.1440 +			endc = element(v, c, c+1);
  1.1441 +			NOERR();
  1.1442 +			break;
  1.1443 +		case COLLEL:
  1.1444 +			startp = v->now;
  1.1445 +			endp = scanplain(v);
  1.1446 +			INSIST(startp < endp, REG_ECOLLATE);
  1.1447 +			NOERR();
  1.1448 +			endc = element(v, startp, endp);
  1.1449 +			NOERR();
  1.1450 +			break;
  1.1451 +		default:
  1.1452 +			ERR(REG_ERANGE);
  1.1453 +			return;
  1.1454 +			break;
  1.1455 +		}
  1.1456 +	} else
  1.1457 +		endc = startc;
  1.1458 +
  1.1459 +	/*
  1.1460 +	 * Ranges are unportable.  Actually, standard C does
  1.1461 +	 * guarantee that digits are contiguous, but making
  1.1462 +	 * that an exception is just too complicated.
  1.1463 +	 */
  1.1464 +	if (startc != endc)
  1.1465 +		NOTE(REG_UUNPORT);
  1.1466 +	cv = range(v, startc, endc, (v->cflags&REG_ICASE));
  1.1467 +	NOERR();
  1.1468 +	dovec(v, cv, lp, rp);
  1.1469 +}
  1.1470 +
  1.1471 +/*
  1.1472 + - scanplain - scan PLAIN contents of [. etc.
  1.1473 + * Certain bits of trickery in lex.c know that this code does not try
  1.1474 + * to look past the final bracket of the [. etc.
  1.1475 + ^ static chr *scanplain(struct vars *);
  1.1476 + */
  1.1477 +static chr *			/* just after end of sequence */
  1.1478 +scanplain(v)
  1.1479 +struct vars *v;
  1.1480 +{
  1.1481 +	chr *endp;
  1.1482 +
  1.1483 +	assert(SEE(COLLEL) || SEE(ECLASS) || SEE(CCLASS));
  1.1484 +	NEXT();
  1.1485 +
  1.1486 +	endp = v->now;
  1.1487 +	while (SEE(PLAIN)) {
  1.1488 +		endp = v->now;
  1.1489 +		NEXT();
  1.1490 +	}
  1.1491 +
  1.1492 +	assert(SEE(END) || ISERR());
  1.1493 +	NEXT();
  1.1494 +
  1.1495 +	return endp;
  1.1496 +}
  1.1497 +
  1.1498 +/*
  1.1499 + - leaders - process a cvec of collating elements to also include leaders
  1.1500 + * Also gives all characters involved their own colors, which is almost
  1.1501 + * certainly necessary, and sets up little disconnected subNFA.
  1.1502 + ^ static VOID leaders(struct vars *, struct cvec *);
  1.1503 + */
  1.1504 +static VOID
  1.1505 +leaders(v, cv)
  1.1506 +struct vars *v;
  1.1507 +struct cvec *cv;
  1.1508 +{
  1.1509 +	int mcce;
  1.1510 +	chr *p;
  1.1511 +	chr leader;
  1.1512 +	struct state *s;
  1.1513 +	struct arc *a;
  1.1514 +
  1.1515 +	v->mccepbegin = newstate(v->nfa);
  1.1516 +	v->mccepend = newstate(v->nfa);
  1.1517 +	NOERR();
  1.1518 +
  1.1519 +	for (mcce = 0; mcce < cv->nmcces; mcce++) {
  1.1520 +		p = cv->mcces[mcce];
  1.1521 +		leader = *p;
  1.1522 +		if (!haschr(cv, leader)) {
  1.1523 +			addchr(cv, leader);
  1.1524 +			s = newstate(v->nfa);
  1.1525 +			newarc(v->nfa, PLAIN, subcolor(v->cm, leader),
  1.1526 +							v->mccepbegin, s);
  1.1527 +			okcolors(v->nfa, v->cm);
  1.1528 +		} else {
  1.1529 +			a = findarc(v->mccepbegin, PLAIN,
  1.1530 +						GETCOLOR(v->cm, leader));
  1.1531 +			assert(a != NULL);
  1.1532 +			s = a->to;
  1.1533 +			assert(s != v->mccepend);
  1.1534 +		}
  1.1535 +		p++;
  1.1536 +		assert(*p != 0 && *(p+1) == 0);	/* only 2-char MCCEs for now */
  1.1537 +		newarc(v->nfa, PLAIN, subcolor(v->cm, *p), s, v->mccepend);
  1.1538 +		okcolors(v->nfa, v->cm);
  1.1539 +	}
  1.1540 +}
  1.1541 +
  1.1542 +/*
  1.1543 + - onechr - fill in arcs for a plain character, and possible case complements
  1.1544 + * This is mostly a shortcut for efficient handling of the common case.
  1.1545 + ^ static VOID onechr(struct vars *, pchr, struct state *, struct state *);
  1.1546 + */
  1.1547 +static VOID
  1.1548 +onechr(v, c, lp, rp)
  1.1549 +struct vars *v;
  1.1550 +pchr c;
  1.1551 +struct state *lp;
  1.1552 +struct state *rp;
  1.1553 +{
  1.1554 +	if (!(v->cflags&REG_ICASE)) {
  1.1555 +		newarc(v->nfa, PLAIN, subcolor(v->cm, c), lp, rp);
  1.1556 +		return;
  1.1557 +	}
  1.1558 +
  1.1559 +	/* rats, need general case anyway... */
  1.1560 +	dovec(v, allcases(v, c), lp, rp);
  1.1561 +}
  1.1562 +
  1.1563 +/*
  1.1564 + - dovec - fill in arcs for each element of a cvec
  1.1565 + * This one has to handle the messy cases, like MCCEs and MCCE leaders.
  1.1566 + ^ static VOID dovec(struct vars *, struct cvec *, struct state *,
  1.1567 + ^ 	struct state *);
  1.1568 + */
  1.1569 +static VOID
  1.1570 +dovec(v, cv, lp, rp)
  1.1571 +struct vars *v;
  1.1572 +struct cvec *cv;
  1.1573 +struct state *lp;
  1.1574 +struct state *rp;
  1.1575 +{
  1.1576 +	chr ch, from, to;
  1.1577 +	celt ce;
  1.1578 +	chr *p;
  1.1579 +	int i;
  1.1580 +	color co;
  1.1581 +	struct cvec *leads;
  1.1582 +	struct arc *a;
  1.1583 +	struct arc *pa;		/* arc in prototype */
  1.1584 +	struct state *s;
  1.1585 +	struct state *ps;	/* state in prototype */
  1.1586 +
  1.1587 +	/* need a place to store leaders, if any */
  1.1588 +	if (nmcces(v) > 0) {
  1.1589 +		assert(v->mcces != NULL);
  1.1590 +		if (v->cv2 == NULL || v->cv2->nchrs < v->mcces->nchrs) {
  1.1591 +			if (v->cv2 != NULL)
  1.1592 +				free(v->cv2);
  1.1593 +			v->cv2 = newcvec(v->mcces->nchrs, 0, v->mcces->nmcces);
  1.1594 +			NOERR();
  1.1595 +			leads = v->cv2;
  1.1596 +		} else
  1.1597 +			leads = clearcvec(v->cv2);
  1.1598 +	} else
  1.1599 +		leads = NULL;
  1.1600 +
  1.1601 +	/* first, get the ordinary characters out of the way */
  1.1602 +	for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--) {
  1.1603 +		ch = *p;
  1.1604 +		if (!ISCELEADER(v, ch))
  1.1605 +			newarc(v->nfa, PLAIN, subcolor(v->cm, ch), lp, rp);
  1.1606 +		else {
  1.1607 +			assert(singleton(v->cm, ch));
  1.1608 +			assert(leads != NULL);
  1.1609 +			if (!haschr(leads, ch))
  1.1610 +				addchr(leads, ch);
  1.1611 +		}
  1.1612 +	}
  1.1613 +
  1.1614 +	/* and the ranges */
  1.1615 +	for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--) {
  1.1616 +		from = *p;
  1.1617 +		to = *(p+1);
  1.1618 +		while (from <= to && (ce = nextleader(v, from, to)) != NOCELT) {
  1.1619 +			if (from < ce)
  1.1620 +				subrange(v, from, ce - 1, lp, rp);
  1.1621 +			assert(singleton(v->cm, ce));
  1.1622 +			assert(leads != NULL);
  1.1623 +			if (!haschr(leads, ce))
  1.1624 +				addchr(leads, ce);
  1.1625 +			from = ce + 1;
  1.1626 +		}
  1.1627 +		if (from <= to)
  1.1628 +			subrange(v, from, to, lp, rp);
  1.1629 +	}
  1.1630 +
  1.1631 +	if ((leads == NULL || leads->nchrs == 0) && cv->nmcces == 0)
  1.1632 +		return;
  1.1633 +
  1.1634 +	/* deal with the MCCE leaders */
  1.1635 +	NOTE(REG_ULOCALE);
  1.1636 +	for (p = leads->chrs, i = leads->nchrs; i > 0; p++, i--) {
  1.1637 +		co = GETCOLOR(v->cm, *p);
  1.1638 +		a = findarc(lp, PLAIN, co);
  1.1639 +		if (a != NULL)
  1.1640 +			s = a->to;
  1.1641 +		else {
  1.1642 +			s = newstate(v->nfa);
  1.1643 +			NOERR();
  1.1644 +			newarc(v->nfa, PLAIN, co, lp, s);
  1.1645 +			NOERR();
  1.1646 +		}
  1.1647 +		pa = findarc(v->mccepbegin, PLAIN, co);
  1.1648 +		assert(pa != NULL);
  1.1649 +		ps = pa->to;
  1.1650 +		newarc(v->nfa, '$', 1, s, rp);
  1.1651 +		newarc(v->nfa, '$', 0, s, rp);
  1.1652 +		colorcomplement(v->nfa, v->cm, AHEAD, ps, s, rp);
  1.1653 +		NOERR();
  1.1654 +	}
  1.1655 +
  1.1656 +	/* and the MCCEs */
  1.1657 +	for (i = 0; i < cv->nmcces; i++) {
  1.1658 +		p = cv->mcces[i];
  1.1659 +		assert(singleton(v->cm, *p));
  1.1660 +		if (!singleton(v->cm, *p)) {
  1.1661 +			ERR(REG_ASSERT);
  1.1662 +			return;
  1.1663 +		}
  1.1664 +		ch = *p++;
  1.1665 +		co = GETCOLOR(v->cm, ch);
  1.1666 +		a = findarc(lp, PLAIN, co);
  1.1667 +		if (a != NULL)
  1.1668 +			s = a->to;
  1.1669 +		else {
  1.1670 +			s = newstate(v->nfa);
  1.1671 +			NOERR();
  1.1672 +			newarc(v->nfa, PLAIN, co, lp, s);
  1.1673 +			NOERR();
  1.1674 +		}
  1.1675 +		assert(*p != 0);	/* at least two chars */
  1.1676 +		assert(singleton(v->cm, *p));
  1.1677 +		ch = *p++;
  1.1678 +		co = GETCOLOR(v->cm, ch);
  1.1679 +		assert(*p == 0);	/* and only two, for now */
  1.1680 +		newarc(v->nfa, PLAIN, co, s, rp);
  1.1681 +		NOERR();
  1.1682 +	}
  1.1683 +}
  1.1684 +
  1.1685 +/*
  1.1686 + - nextleader - find next MCCE leader within range
  1.1687 + ^ static celt nextleader(struct vars *, pchr, pchr);
  1.1688 + */
  1.1689 +static celt			/* NOCELT means none */
  1.1690 +nextleader(v, from, to)
  1.1691 +struct vars *v;
  1.1692 +pchr from;
  1.1693 +pchr to;
  1.1694 +{
  1.1695 +	int i;
  1.1696 +	chr *p;
  1.1697 +	chr ch;
  1.1698 +	celt it = NOCELT;
  1.1699 +
  1.1700 +	if (v->mcces == NULL)
  1.1701 +		return it;
  1.1702 +
  1.1703 +	for (i = v->mcces->nchrs, p = v->mcces->chrs; i > 0; i--, p++) {
  1.1704 +		ch = *p;
  1.1705 +		if (from <= ch && ch <= to)
  1.1706 +			if (it == NOCELT || ch < it)
  1.1707 +				it = ch;
  1.1708 +	}
  1.1709 +	return it;
  1.1710 +}
  1.1711 +
  1.1712 +/*
  1.1713 + - wordchrs - set up word-chr list for word-boundary stuff, if needed
  1.1714 + * The list is kept as a bunch of arcs between two dummy states; it's
  1.1715 + * disposed of by the unreachable-states sweep in NFA optimization.
  1.1716 + * Does NEXT().  Must not be called from any unusual lexical context.
  1.1717 + * This should be reconciled with the \w etc. handling in lex.c, and
  1.1718 + * should be cleaned up to reduce dependencies on input scanning.
  1.1719 + ^ static VOID wordchrs(struct vars *);
  1.1720 + */
  1.1721 +static VOID
  1.1722 +wordchrs(v)
  1.1723 +struct vars *v;
  1.1724 +{
  1.1725 +	struct state *left;
  1.1726 +	struct state *right;
  1.1727 +
  1.1728 +	if (v->wordchrs != NULL) {
  1.1729 +		NEXT();		/* for consistency */
  1.1730 +		return;
  1.1731 +	}
  1.1732 +
  1.1733 +	left = newstate(v->nfa);
  1.1734 +	right = newstate(v->nfa);
  1.1735 +	NOERR();
  1.1736 +	/* fine point:  implemented with [::], and lexer will set REG_ULOCALE */
  1.1737 +	lexword(v);
  1.1738 +	NEXT();
  1.1739 +	assert(v->savenow != NULL && SEE('['));
  1.1740 +	bracket(v, left, right);
  1.1741 +	assert((v->savenow != NULL && SEE(']')) || ISERR());
  1.1742 +	NEXT();
  1.1743 +	NOERR();
  1.1744 +	v->wordchrs = left;
  1.1745 +}
  1.1746 +
  1.1747 +/*
  1.1748 + - subre - allocate a subre
  1.1749 + ^ static struct subre *subre(struct vars *, int, int, struct state *,
  1.1750 + ^	struct state *);
  1.1751 + */
  1.1752 +static struct subre *
  1.1753 +subre(v, op, flags, begin, end)
  1.1754 +struct vars *v;
  1.1755 +int op;
  1.1756 +int flags;
  1.1757 +struct state *begin;
  1.1758 +struct state *end;
  1.1759 +{
  1.1760 +	struct subre *ret;
  1.1761 +
  1.1762 +	ret = v->treefree;
  1.1763 +	if (ret != NULL)
  1.1764 +		v->treefree = ret->left;
  1.1765 +	else {
  1.1766 +		ret = (struct subre *)MALLOC(sizeof(struct subre));
  1.1767 +		if (ret == NULL) {
  1.1768 +			ERR(REG_ESPACE);
  1.1769 +			return NULL;
  1.1770 +		}
  1.1771 +		ret->chain = v->treechain;
  1.1772 +		v->treechain = ret;
  1.1773 +	}
  1.1774 +
  1.1775 +	assert(strchr("|.b(=", op) != NULL);
  1.1776 +
  1.1777 +	ret->op = op;
  1.1778 +	ret->flags = flags;
  1.1779 +	ret->retry = 0;
  1.1780 +	ret->subno = 0;
  1.1781 +	ret->min = ret->max = 1;
  1.1782 +	ret->left = NULL;
  1.1783 +	ret->right = NULL;
  1.1784 +	ret->begin = begin;
  1.1785 +	ret->end = end;
  1.1786 +	ZAPCNFA(ret->cnfa);
  1.1787 +
  1.1788 +	return ret;
  1.1789 +}
  1.1790 +
  1.1791 +/*
  1.1792 + - freesubre - free a subRE subtree
  1.1793 + ^ static VOID freesubre(struct vars *, struct subre *);
  1.1794 + */
  1.1795 +static VOID
  1.1796 +freesubre(v, sr)
  1.1797 +struct vars *v;			/* might be NULL */
  1.1798 +struct subre *sr;
  1.1799 +{
  1.1800 +	if (sr == NULL)
  1.1801 +		return;
  1.1802 +
  1.1803 +	if (sr->left != NULL)
  1.1804 +		freesubre(v, sr->left);
  1.1805 +	if (sr->right != NULL)
  1.1806 +		freesubre(v, sr->right);
  1.1807 +
  1.1808 +	freesrnode(v, sr);
  1.1809 +}
  1.1810 +
  1.1811 +/*
  1.1812 + - freesrnode - free one node in a subRE subtree
  1.1813 + ^ static VOID freesrnode(struct vars *, struct subre *);
  1.1814 + */
  1.1815 +static VOID
  1.1816 +freesrnode(v, sr)
  1.1817 +struct vars *v;			/* might be NULL */
  1.1818 +struct subre *sr;
  1.1819 +{
  1.1820 +	if (sr == NULL)
  1.1821 +		return;
  1.1822 +
  1.1823 +	if (!NULLCNFA(sr->cnfa))
  1.1824 +		freecnfa(&sr->cnfa);
  1.1825 +	sr->flags = 0;
  1.1826 +
  1.1827 +	if (v != NULL) {
  1.1828 +		sr->left = v->treefree;
  1.1829 +		v->treefree = sr;
  1.1830 +	} else
  1.1831 +		FREE(sr);
  1.1832 +}
  1.1833 +
  1.1834 +/*
  1.1835 + - optst - optimize a subRE subtree
  1.1836 + ^ static VOID optst(struct vars *, struct subre *);
  1.1837 + */
  1.1838 +static VOID
  1.1839 +optst(v, t)
  1.1840 +struct vars *v;
  1.1841 +struct subre *t;
  1.1842 +{
  1.1843 +	if (t == NULL)
  1.1844 +		return;
  1.1845 +
  1.1846 +	/* recurse through children */
  1.1847 +	if (t->left != NULL)
  1.1848 +		optst(v, t->left);
  1.1849 +	if (t->right != NULL)
  1.1850 +		optst(v, t->right);
  1.1851 +}
  1.1852 +
  1.1853 +/*
  1.1854 + - numst - number tree nodes (assigning retry indexes)
  1.1855 + ^ static int numst(struct subre *, int);
  1.1856 + */
  1.1857 +static int			/* next number */
  1.1858 +numst(t, start)
  1.1859 +struct subre *t;
  1.1860 +int start;			/* starting point for subtree numbers */
  1.1861 +{
  1.1862 +	int i;
  1.1863 +
  1.1864 +	assert(t != NULL);
  1.1865 +
  1.1866 +	i = start;
  1.1867 +	t->retry = (short)i++;
  1.1868 +	if (t->left != NULL)
  1.1869 +		i = numst(t->left, i);
  1.1870 +	if (t->right != NULL)
  1.1871 +		i = numst(t->right, i);
  1.1872 +	return i;
  1.1873 +}
  1.1874 +
  1.1875 +/*
  1.1876 + - markst - mark tree nodes as INUSE
  1.1877 + ^ static VOID markst(struct subre *);
  1.1878 + */
  1.1879 +static VOID
  1.1880 +markst(t)
  1.1881 +struct subre *t;
  1.1882 +{
  1.1883 +	assert(t != NULL);
  1.1884 +
  1.1885 +	t->flags |= INUSE;
  1.1886 +	if (t->left != NULL)
  1.1887 +		markst(t->left);
  1.1888 +	if (t->right != NULL)
  1.1889 +		markst(t->right);
  1.1890 +}
  1.1891 +
  1.1892 +/*
  1.1893 + - cleanst - free any tree nodes not marked INUSE
  1.1894 + ^ static VOID cleanst(struct vars *);
  1.1895 + */
  1.1896 +static VOID
  1.1897 +cleanst(v)
  1.1898 +struct vars *v;
  1.1899 +{
  1.1900 +	struct subre *t;
  1.1901 +	struct subre *next;
  1.1902 +
  1.1903 +	for (t = v->treechain; t != NULL; t = next) {
  1.1904 +		next = t->chain;
  1.1905 +		if (!(t->flags&INUSE))
  1.1906 +			FREE(t);
  1.1907 +	}
  1.1908 +	v->treechain = NULL;
  1.1909 +	v->treefree = NULL;		/* just on general principles */
  1.1910 +}
  1.1911 +
  1.1912 +/*
  1.1913 + - nfatree - turn a subRE subtree into a tree of compacted NFAs
  1.1914 + ^ static long nfatree(struct vars *, struct subre *, FILE *);
  1.1915 + */
  1.1916 +static long			/* optimize results from top node */
  1.1917 +nfatree(v, t, f)
  1.1918 +struct vars *v;
  1.1919 +struct subre *t;
  1.1920 +FILE *f;			/* for debug output */
  1.1921 +{
  1.1922 +	assert(t != NULL && t->begin != NULL);
  1.1923 +
  1.1924 +	if (t->left != NULL)
  1.1925 +		(DISCARD)nfatree(v, t->left, f);
  1.1926 +	if (t->right != NULL)
  1.1927 +		(DISCARD)nfatree(v, t->right, f);
  1.1928 +
  1.1929 +	return nfanode(v, t, f);
  1.1930 +}
  1.1931 +
  1.1932 +/*
  1.1933 + - nfanode - do one NFA for nfatree
  1.1934 + ^ static long nfanode(struct vars *, struct subre *, FILE *);
  1.1935 + */
  1.1936 +static long			/* optimize results */
  1.1937 +nfanode(v, t, f)
  1.1938 +struct vars *v;
  1.1939 +struct subre *t;
  1.1940 +FILE *f;			/* for debug output */
  1.1941 +{
  1.1942 +	struct nfa *nfa;
  1.1943 +	long ret = 0;
  1.1944 +	char idbuf[50];
  1.1945 +
  1.1946 +	assert(t->begin != NULL);
  1.1947 +
  1.1948 +	if (f != NULL)
  1.1949 +		fprintf(f, "\n\n\n========= TREE NODE %s ==========\n",
  1.1950 +						stid(t, idbuf, sizeof(idbuf)));
  1.1951 +	nfa = newnfa(v, v->cm, v->nfa);
  1.1952 +	NOERRZ();
  1.1953 +	dupnfa(nfa, t->begin, t->end, nfa->init, nfa->final);
  1.1954 +	if (!ISERR()) {
  1.1955 +		specialcolors(nfa);
  1.1956 +		ret = optimize(nfa, f);
  1.1957 +	}
  1.1958 +	if (!ISERR())
  1.1959 +		compact(nfa, &t->cnfa);
  1.1960 +
  1.1961 +	freenfa(nfa);
  1.1962 +	return ret;
  1.1963 +}
  1.1964 +
  1.1965 +/*
  1.1966 + - newlacon - allocate a lookahead-constraint subRE
  1.1967 + ^ static int newlacon(struct vars *, struct state *, struct state *, int);
  1.1968 + */
  1.1969 +static int			/* lacon number */
  1.1970 +newlacon(v, begin, end, pos)
  1.1971 +struct vars *v;
  1.1972 +struct state *begin;
  1.1973 +struct state *end;
  1.1974 +int pos;
  1.1975 +{
  1.1976 +	int n;
  1.1977 +	struct subre *sub;
  1.1978 +
  1.1979 +	if (v->nlacons == 0) {
  1.1980 +		v->lacons = (struct subre *)MALLOC(2 * sizeof(struct subre));
  1.1981 +		n = 1;		/* skip 0th */
  1.1982 +		v->nlacons = 2;
  1.1983 +	} else {
  1.1984 +		v->lacons = (struct subre *)REALLOC(v->lacons,
  1.1985 +					(v->nlacons+1)*sizeof(struct subre));
  1.1986 +		n = v->nlacons++;
  1.1987 +	}
  1.1988 +	if (v->lacons == NULL) {
  1.1989 +		ERR(REG_ESPACE);
  1.1990 +		return 0;
  1.1991 +	}
  1.1992 +	sub = &v->lacons[n];
  1.1993 +	sub->begin = begin;
  1.1994 +	sub->end = end;
  1.1995 +	sub->subno = pos;
  1.1996 +	ZAPCNFA(sub->cnfa);
  1.1997 +	return n;
  1.1998 +}
  1.1999 +
  1.2000 +/*
  1.2001 + - freelacons - free lookahead-constraint subRE vector
  1.2002 + ^ static VOID freelacons(struct subre *, int);
  1.2003 + */
  1.2004 +static VOID
  1.2005 +freelacons(subs, n)
  1.2006 +struct subre *subs;
  1.2007 +int n;
  1.2008 +{
  1.2009 +	struct subre *sub;
  1.2010 +	int i;
  1.2011 +
  1.2012 +	assert(n > 0);
  1.2013 +	for (sub = subs + 1, i = n - 1; i > 0; sub++, i--)	/* no 0th */
  1.2014 +		if (!NULLCNFA(sub->cnfa))
  1.2015 +			freecnfa(&sub->cnfa);
  1.2016 +	FREE(subs);
  1.2017 +}
  1.2018 +
  1.2019 +/*
  1.2020 + - rfree - free a whole RE (insides of regfree)
  1.2021 + ^ static VOID rfree(regex_t *);
  1.2022 + */
  1.2023 +static VOID
  1.2024 +rfree(re)
  1.2025 +regex_t *re;
  1.2026 +{
  1.2027 +	struct guts *g;
  1.2028 +
  1.2029 +	if (re == NULL || re->re_magic != REMAGIC)
  1.2030 +		return;
  1.2031 +
  1.2032 +	re->re_magic = 0;	/* invalidate RE */
  1.2033 +	g = (struct guts *)re->re_guts;
  1.2034 +	re->re_guts = NULL;
  1.2035 +	re->re_fns = NULL;
  1.2036 +	g->magic = 0;
  1.2037 +	freecm(&g->cmap);
  1.2038 +	if (g->tree != NULL)
  1.2039 +		freesubre((struct vars *)NULL, g->tree);
  1.2040 +	if (g->lacons != NULL)
  1.2041 +		freelacons(g->lacons, g->nlacons);
  1.2042 +	if (!NULLCNFA(g->search))
  1.2043 +		freecnfa(&g->search);
  1.2044 +	FREE(g);
  1.2045 +}
  1.2046 +
  1.2047 +/*
  1.2048 + - dump - dump an RE in human-readable form
  1.2049 + ^ static VOID dump(regex_t *, FILE *);
  1.2050 + */
  1.2051 +static VOID
  1.2052 +dump(re, f)
  1.2053 +regex_t *re;
  1.2054 +FILE *f;
  1.2055 +{
  1.2056 +#ifdef REG_DEBUG
  1.2057 +	struct guts *g;
  1.2058 +	int i;
  1.2059 +
  1.2060 +	if (re->re_magic != REMAGIC)
  1.2061 +		fprintf(f, "bad magic number (0x%x not 0x%x)\n", re->re_magic,
  1.2062 +								REMAGIC);
  1.2063 +	if (re->re_guts == NULL) {
  1.2064 +		fprintf(f, "NULL guts!!!\n");
  1.2065 +		return;
  1.2066 +	}
  1.2067 +	g = (struct guts *)re->re_guts;
  1.2068 +	if (g->magic != GUTSMAGIC)
  1.2069 +		fprintf(f, "bad guts magic number (0x%x not 0x%x)\n", g->magic,
  1.2070 +								GUTSMAGIC);
  1.2071 +
  1.2072 +	fprintf(f, "\n\n\n========= DUMP ==========\n");
  1.2073 +	fprintf(f, "nsub %d, info 0%lo, csize %d, ntree %d\n", 
  1.2074 +		re->re_nsub, re->re_info, re->re_csize, g->ntree);
  1.2075 +
  1.2076 +	dumpcolors(&g->cmap, f);
  1.2077 +	if (!NULLCNFA(g->search)) {
  1.2078 +		printf("\nsearch:\n");
  1.2079 +		dumpcnfa(&g->search, f);
  1.2080 +	}
  1.2081 +	for (i = 1; i < g->nlacons; i++) {
  1.2082 +		fprintf(f, "\nla%d (%s):\n", i,
  1.2083 +				(g->lacons[i].subno) ? "positive" : "negative");
  1.2084 +		dumpcnfa(&g->lacons[i].cnfa, f);
  1.2085 +	}
  1.2086 +	fprintf(f, "\n");
  1.2087 +	dumpst(g->tree, f, 0);
  1.2088 +#endif
  1.2089 +}
  1.2090 +
  1.2091 +/*
  1.2092 + - dumpst - dump a subRE tree
  1.2093 + ^ static VOID dumpst(struct subre *, FILE *, int);
  1.2094 + */
  1.2095 +static VOID
  1.2096 +dumpst(t, f, nfapresent)
  1.2097 +struct subre *t;
  1.2098 +FILE *f;
  1.2099 +int nfapresent;			/* is the original NFA still around? */
  1.2100 +{
  1.2101 +	if (t == NULL)
  1.2102 +		fprintf(f, "null tree\n");
  1.2103 +	else
  1.2104 +		stdump(t, f, nfapresent);
  1.2105 +	fflush(f);
  1.2106 +}
  1.2107 +
  1.2108 +/*
  1.2109 + - stdump - recursive guts of dumpst
  1.2110 + ^ static VOID stdump(struct subre *, FILE *, int);
  1.2111 + */
  1.2112 +static VOID
  1.2113 +stdump(t, f, nfapresent)
  1.2114 +struct subre *t;
  1.2115 +FILE *f;
  1.2116 +int nfapresent;			/* is the original NFA still around? */
  1.2117 +{
  1.2118 +	char idbuf[50];
  1.2119 +
  1.2120 +	fprintf(f, "%s. `%c'", stid(t, idbuf, sizeof(idbuf)), t->op);
  1.2121 +	if (t->flags&LONGER)
  1.2122 +		fprintf(f, " longest");
  1.2123 +	if (t->flags&SHORTER)
  1.2124 +		fprintf(f, " shortest");
  1.2125 +	if (t->flags&MIXED)
  1.2126 +		fprintf(f, " hasmixed");
  1.2127 +	if (t->flags&CAP)
  1.2128 +		fprintf(f, " hascapture");
  1.2129 +	if (t->flags&BACKR)
  1.2130 +		fprintf(f, " hasbackref");
  1.2131 +	if (!(t->flags&INUSE))
  1.2132 +		fprintf(f, " UNUSED");
  1.2133 +	if (t->subno != 0)
  1.2134 +		fprintf(f, " (#%d)", t->subno);
  1.2135 +	if (t->min != 1 || t->max != 1) {
  1.2136 +		fprintf(f, " {%d,", t->min);
  1.2137 +		if (t->max != INFINITY)
  1.2138 +			fprintf(f, "%d", t->max);
  1.2139 +		fprintf(f, "}");
  1.2140 +	}
  1.2141 +	if (nfapresent)
  1.2142 +		fprintf(f, " %ld-%ld", (long)t->begin->no, (long)t->end->no);
  1.2143 +	if (t->left != NULL)
  1.2144 +		fprintf(f, " L:%s", stid(t->left, idbuf, sizeof(idbuf)));
  1.2145 +	if (t->right != NULL)
  1.2146 +		fprintf(f, " R:%s", stid(t->right, idbuf, sizeof(idbuf)));
  1.2147 +	if (!NULLCNFA(t->cnfa)) {
  1.2148 +		fprintf(f, "\n");
  1.2149 +		dumpcnfa(&t->cnfa, f);
  1.2150 +		fprintf(f, "\n");
  1.2151 +	}
  1.2152 +	if (t->left != NULL)
  1.2153 +		stdump(t->left, f, nfapresent);
  1.2154 +	if (t->right != NULL)
  1.2155 +		stdump(t->right, f, nfapresent);
  1.2156 +}
  1.2157 +
  1.2158 +/*
  1.2159 + - stid - identify a subtree node for dumping
  1.2160 + ^ static char *stid(struct subre *, char *, size_t);
  1.2161 + */
  1.2162 +static char *			/* points to buf or constant string */
  1.2163 +stid(t, buf, bufsize)
  1.2164 +struct subre *t;
  1.2165 +char *buf;
  1.2166 +size_t bufsize;
  1.2167 +{
  1.2168 +	/* big enough for hex int or decimal t->retry? */
  1.2169 +	if (bufsize < sizeof(void*)*2 + 3 || bufsize < sizeof(t->retry)*3 + 1)
  1.2170 +		return "unable";
  1.2171 +	if (t->retry != 0)
  1.2172 +		sprintf(buf, "%d", t->retry);
  1.2173 +	else
  1.2174 +		sprintf(buf, "%p", t);
  1.2175 +	return buf;
  1.2176 +}
  1.2177 +
  1.2178 +#include "regc_lex.c"
  1.2179 +#include "regc_color.c"
  1.2180 +#include "regc_nfa.c"
  1.2181 +#include "regc_cvec.c"
  1.2182 +#include "regc_locale.c"