changeset 18019:68fd5296bf73 v8.1.2005

patch 8.1.2005: the regexp.c file is too big Commit: https://github.com/vim/vim/commit/6d7d7cf750bca5d641e464f6a3af5ee5b99a5ac8 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Sep 7 23:16:33 2019 +0200 patch 8.1.2005: the regexp.c file is too big Problem: The regexp.c file is too big. Solution: Move the backtracking engine to a separate file. (Yegappan Lakshmanan, closes #4905)
author Bram Moolenaar <Bram@vim.org>
date Sat, 07 Sep 2019 23:30:04 +0200
parents 08fb5a871e6b
children 1a1df6898465
files Filelist src/Make_cyg_ming.mak src/Make_mvc.mak src/Makefile src/regexp.c src/regexp_bt.c src/version.c
diffstat 7 files changed, 5418 insertions(+), 5450 deletions(-) [+]
line wrap: on
line diff
--- a/Filelist
+++ b/Filelist
@@ -92,6 +92,7 @@ SRC_ALL =	\
 		src/profiler.c \
 		src/quickfix.c \
 		src/regexp.c \
+		src/regexp_bt.c \
 		src/regexp_nfa.c \
 		src/regexp.h \
 		src/scriptfile.c \
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -1179,7 +1179,7 @@ endif
 $(OUTDIR)/os_win32.o:	os_win32.c $(INCL) $(MZSCHEME_INCL)
 	$(CC) -c $(CFLAGS) os_win32.c -o $@
 
-$(OUTDIR)/regexp.o:	regexp.c regexp_nfa.c $(INCL)
+$(OUTDIR)/regexp.o:	regexp.c regexp_bt.c regexp_nfa.c $(INCL)
 	$(CC) -c $(CFLAGS) regexp.c -o $@
 
 $(OUTDIR)/terminal.o:	terminal.c $(INCL) $(TERM_DEPS)
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -1637,7 +1637,7 @@ lib$(MZSCHEME_MAIN_LIB)$(MZSCHEME_VER).l
 
 $(OUTDIR)/quickfix.obj:	$(OUTDIR) quickfix.c  $(INCL)
 
-$(OUTDIR)/regexp.obj:	$(OUTDIR) regexp.c regexp_nfa.c  $(INCL)
+$(OUTDIR)/regexp.obj:	$(OUTDIR) regexp.c regexp_bt.c regexp_nfa.c  $(INCL)
 
 $(OUTDIR)/scriptfile.obj:	$(OUTDIR) scriptfile.c  $(INCL)
 
--- a/src/Makefile
+++ b/src/Makefile
@@ -3326,7 +3326,7 @@ objects/pty.o: pty.c
 objects/quickfix.o: quickfix.c
 	$(CCC) -o $@ quickfix.c
 
-objects/regexp.o: regexp.c regexp_nfa.c
+objects/regexp.o: regexp.c regexp_bt.c regexp_nfa.c
 	$(CCC) -o $@ regexp.c
 
 objects/scriptfile.o: scriptfile.c
@@ -3794,7 +3794,7 @@ objects/quickfix.o: quickfix.c vim.h pro
 objects/regexp.o: regexp.c vim.h protodef.h auto/config.h feature.h os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
- proto.h globals.h regexp_nfa.c
+ proto.h globals.h regexp_bt.c regexp_nfa.c
 objects/scriptfile.o: scriptfile.c vim.h protodef.h auto/config.h feature.h os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -1,41 +1,6 @@
 /* vi:set ts=8 sts=4 sw=4 noet:
  *
  * Handling of regular expressions: vim_regcomp(), vim_regexec(), vim_regsub()
- *
- * NOTICE:
- *
- * This is NOT the original regular expression code as written by Henry
- * Spencer.  This code has been modified specifically for use with the VIM
- * editor, and should not be used separately from Vim.  If you want a good
- * regular expression library, get the original code.  The copyright notice
- * that follows is from the original.
- *
- * END NOTICE
- *
- *	Copyright (c) 1986 by University of Toronto.
- *	Written by Henry Spencer.  Not derived from licensed software.
- *
- *	Permission is granted to anyone to use this software for any
- *	purpose on any computer system, and to redistribute it freely,
- *	subject to the following restrictions:
- *
- *	1. The author is not responsible for the consequences of use of
- *		this software, no matter how awful, even if they arise
- *		from defects in it.
- *
- *	2. The origin of this software must not be misrepresented, either
- *		by explicit claim or by omission.
- *
- *	3. Altered versions must be plainly marked as such, and must not
- *		be misrepresented as being the original software.
- *
- * Beware that some of this code is subtly aware of the way operator
- * precedence is structured in regular expressions.  Serious changes in
- * regular-expression syntax might require a total rethink.
- *
- * Changes have been made by Tony Andrews, Olaf 'Rhialto' Seibert, Robert
- * Webb, Ciaran McCreesh and Bram Moolenaar.
- * Named character class support added by Walter Briscoe (1998 Jul 01)
  */
 
 // By default: do not create debugging logs or files related to regular
@@ -56,197 +21,6 @@
 #endif
 
 /*
- * The "internal use only" fields in regexp.h are present to pass info from
- * compile to execute that permits the execute phase to run lots faster on
- * simple cases.  They are:
- *
- * regstart	char that must begin a match; NUL if none obvious; Can be a
- *		multi-byte character.
- * reganch	is the match anchored (at beginning-of-line only)?
- * regmust	string (pointer into program) that match must include, or NULL
- * regmlen	length of regmust string
- * regflags	RF_ values or'ed together
- *
- * Regstart and reganch permit very fast decisions on suitable starting points
- * for a match, cutting down the work a lot.  Regmust permits fast rejection
- * of lines that cannot possibly match.  The regmust tests are costly enough
- * that vim_regcomp() supplies a regmust only if the r.e. contains something
- * potentially expensive (at present, the only such thing detected is * or +
- * at the start of the r.e., which can involve a lot of backup).  Regmlen is
- * supplied because the test in vim_regexec() needs it and vim_regcomp() is
- * computing it anyway.
- */
-
-/*
- * Structure for regexp "program".  This is essentially a linear encoding
- * of a nondeterministic finite-state machine (aka syntax charts or
- * "railroad normal form" in parsing technology).  Each node is an opcode
- * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
- * all nodes except BRANCH and BRACES_COMPLEX implement concatenation; a "next"
- * pointer with a BRANCH on both ends of it is connecting two alternatives.
- * (Here we have one of the subtle syntax dependencies:	an individual BRANCH
- * (as opposed to a collection of them) is never concatenated with anything
- * because of operator precedence).  The "next" pointer of a BRACES_COMPLEX
- * node points to the node after the stuff to be repeated.
- * The operand of some types of node is a literal string; for others, it is a
- * node leading into a sub-FSM.  In particular, the operand of a BRANCH node
- * is the first node of the branch.
- * (NB this is *not* a tree structure: the tail of the branch connects to the
- * thing following the set of BRANCHes.)
- *
- * pattern	is coded like:
- *
- *			  +-----------------+
- *			  |		    V
- * <aa>\|<bb>	BRANCH <aa> BRANCH <bb> --> END
- *		     |	    ^	 |	    ^
- *		     +------+	 +----------+
- *
- *
- *		       +------------------+
- *		       V		  |
- * <aa>*	BRANCH BRANCH <aa> --> BACK BRANCH --> NOTHING --> END
- *		     |	    |		    ^			   ^
- *		     |	    +---------------+			   |
- *		     +---------------------------------------------+
- *
- *
- *		       +----------------------+
- *		       V		      |
- * <aa>\+	BRANCH <aa> --> BRANCH --> BACK  BRANCH --> NOTHING --> END
- *		     |		     |		 ^			^
- *		     |		     +-----------+			|
- *		     +--------------------------------------------------+
- *
- *
- *					+-------------------------+
- *					V			  |
- * <aa>\{}	BRANCH BRACE_LIMITS --> BRACE_COMPLEX <aa> --> BACK  END
- *		     |				    |		     ^
- *		     |				    +----------------+
- *		     +-----------------------------------------------+
- *
- *
- * <aa>\@!<bb>	BRANCH NOMATCH <aa> --> END  <bb> --> END
- *		     |	     |		      ^       ^
- *		     |	     +----------------+       |
- *		     +--------------------------------+
- *
- *						      +---------+
- *						      |		V
- * \z[abc]	BRANCH BRANCH  a  BRANCH  b  BRANCH  c	BRANCH	NOTHING --> END
- *		     |	    |	       |	  |	^		    ^
- *		     |	    |	       |	  +-----+		    |
- *		     |	    |	       +----------------+		    |
- *		     |	    +---------------------------+		    |
- *		     +------------------------------------------------------+
- *
- * They all start with a BRANCH for "\|" alternatives, even when there is only
- * one alternative.
- */
-
-/*
- * The opcodes are:
- */
-
-/* definition	number		   opnd?    meaning */
-#define END		0	/*	End of program or NOMATCH operand. */
-#define BOL		1	/*	Match "" at beginning of line. */
-#define EOL		2	/*	Match "" at end of line. */
-#define BRANCH		3	/* node Match this alternative, or the
-				 *	next... */
-#define BACK		4	/*	Match "", "next" ptr points backward. */
-#define EXACTLY		5	/* str	Match this string. */
-#define NOTHING		6	/*	Match empty string. */
-#define STAR		7	/* node Match this (simple) thing 0 or more
-				 *	times. */
-#define PLUS		8	/* node Match this (simple) thing 1 or more
-				 *	times. */
-#define MATCH		9	/* node match the operand zero-width */
-#define NOMATCH		10	/* node check for no match with operand */
-#define BEHIND		11	/* node look behind for a match with operand */
-#define NOBEHIND	12	/* node look behind for no match with operand */
-#define SUBPAT		13	/* node match the operand here */
-#define BRACE_SIMPLE	14	/* node Match this (simple) thing between m and
-				 *	n times (\{m,n\}). */
-#define BOW		15	/*	Match "" after [^a-zA-Z0-9_] */
-#define EOW		16	/*	Match "" at    [^a-zA-Z0-9_] */
-#define BRACE_LIMITS	17	/* nr nr  define the min & max for BRACE_SIMPLE
-				 *	and BRACE_COMPLEX. */
-#define NEWL		18	/*	Match line-break */
-#define BHPOS		19	/*	End position for BEHIND or NOBEHIND */
-
-
-/* character classes: 20-48 normal, 50-78 include a line-break */
-#define ADD_NL		30
-#define FIRST_NL	ANY + ADD_NL
-#define ANY		20	/*	Match any one character. */
-#define ANYOF		21	/* str	Match any character in this string. */
-#define ANYBUT		22	/* str	Match any character not in this
-				 *	string. */
-#define IDENT		23	/*	Match identifier char */
-#define SIDENT		24	/*	Match identifier char but no digit */
-#define KWORD		25	/*	Match keyword char */
-#define SKWORD		26	/*	Match word char but no digit */
-#define FNAME		27	/*	Match file name char */
-#define SFNAME		28	/*	Match file name char but no digit */
-#define PRINT		29	/*	Match printable char */
-#define SPRINT		30	/*	Match printable char but no digit */
-#define WHITE		31	/*	Match whitespace char */
-#define NWHITE		32	/*	Match non-whitespace char */
-#define DIGIT		33	/*	Match digit char */
-#define NDIGIT		34	/*	Match non-digit char */
-#define HEX		35	/*	Match hex char */
-#define NHEX		36	/*	Match non-hex char */
-#define OCTAL		37	/*	Match octal char */
-#define NOCTAL		38	/*	Match non-octal char */
-#define WORD		39	/*	Match word char */
-#define NWORD		40	/*	Match non-word char */
-#define HEAD		41	/*	Match head char */
-#define NHEAD		42	/*	Match non-head char */
-#define ALPHA		43	/*	Match alpha char */
-#define NALPHA		44	/*	Match non-alpha char */
-#define LOWER		45	/*	Match lowercase char */
-#define NLOWER		46	/*	Match non-lowercase char */
-#define UPPER		47	/*	Match uppercase char */
-#define NUPPER		48	/*	Match non-uppercase char */
-#define LAST_NL		NUPPER + ADD_NL
-#define WITH_NL(op)	((op) >= FIRST_NL && (op) <= LAST_NL)
-
-#define MOPEN		80  /* -89	 Mark this point in input as start of
-				 *	 \( subexpr.  MOPEN + 0 marks start of
-				 *	 match. */
-#define MCLOSE		90  /* -99	 Analogous to MOPEN.  MCLOSE + 0 marks
-				 *	 end of match. */
-#define BACKREF		100 /* -109 node Match same string again \1-\9 */
-
-#ifdef FEAT_SYN_HL
-# define ZOPEN		110 /* -119	 Mark this point in input as start of
-				 *	 \z( subexpr. */
-# define ZCLOSE		120 /* -129	 Analogous to ZOPEN. */
-# define ZREF		130 /* -139 node Match external submatch \z1-\z9 */
-#endif
-
-#define BRACE_COMPLEX	140 /* -149 node Match nodes between m & n times */
-
-#define NOPEN		150	/*	Mark this point in input as start of
-					\%( subexpr. */
-#define NCLOSE		151	/*	Analogous to NOPEN. */
-
-#define MULTIBYTECODE	200	/* mbc	Match one multi-byte character */
-#define RE_BOF		201	/*	Match "" at beginning of file. */
-#define RE_EOF		202	/*	Match "" at end of file. */
-#define CURSOR		203	/*	Match location of cursor. */
-
-#define RE_LNUM		204	/* nr cmp  Match line number */
-#define RE_COL		205	/* nr cmp  Match column number */
-#define RE_VCOL		206	/* nr cmp  Match virtual column number */
-
-#define RE_MARK		207	/* mark cmp  Match mark position */
-#define RE_VISUAL	208	/*	Match Visual area */
-#define RE_COMPOSING	209	/* any composing characters */
-
-/*
  * Magic characters have a special meaning, they don't match literally.
  * Magic characters are negative.  This separates them from literal characters
  * (possibly multi-byte).  Only ASCII characters can be Magic.
@@ -272,7 +46,7 @@ toggle_Magic(int x)
 }
 
 /*
- * The first byte of the regexp internal "program" is actually this magic
+ * The first byte of the BT regexp internal "program" is actually this magic
  * number; the start node begins in the second byte.  It's used to catch the
  * most severe mutilation of the program by the caller.
  */
@@ -280,54 +54,6 @@ toggle_Magic(int x)
 #define REGMAGIC	0234
 
 /*
- * Opcode notes:
- *
- * BRANCH	The set of branches constituting a single choice are hooked
- *		together with their "next" pointers, since precedence prevents
- *		anything being concatenated to any individual branch.  The
- *		"next" pointer of the last BRANCH in a choice points to the
- *		thing following the whole choice.  This is also where the
- *		final "next" pointer of each individual branch points; each
- *		branch starts with the operand node of a BRANCH node.
- *
- * BACK		Normal "next" pointers all implicitly point forward; BACK
- *		exists to make loop structures possible.
- *
- * STAR,PLUS	'=', and complex '*' and '+', are implemented as circular
- *		BRANCH structures using BACK.  Simple cases (one character
- *		per match) are implemented with STAR and PLUS for speed
- *		and to minimize recursive plunges.
- *
- * BRACE_LIMITS	This is always followed by a BRACE_SIMPLE or BRACE_COMPLEX
- *		node, and defines the min and max limits to be used for that
- *		node.
- *
- * MOPEN,MCLOSE	...are numbered at compile time.
- * ZOPEN,ZCLOSE	...ditto
- */
-
-/*
- * A node is one char of opcode followed by two chars of "next" pointer.
- * "Next" pointers are stored as two 8-bit bytes, high order first.  The
- * value is a positive offset from the opcode of the node containing it.
- * An operand, if any, simply follows the node.  (Note that much of the
- * code generation knows about this implicit relationship.)
- *
- * Using two bytes for the "next" pointer is vast overkill for most things,
- * but allows patterns to get big without disasters.
- */
-#define OP(p)		((int)*(p))
-#define NEXT(p)		(((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377))
-#define OPERAND(p)	((p) + 3)
-/* Obtain an operand that was stored as four bytes, MSB first. */
-#define OPERAND_MIN(p)	(((long)(p)[3] << 24) + ((long)(p)[4] << 16) \
-			+ ((long)(p)[5] << 8) + (long)(p)[6])
-/* Obtain a second operand stored as four bytes. */
-#define OPERAND_MAX(p)	OPERAND_MIN((p) + 4)
-/* Obtain a second single-byte operand stored after a four bytes operand. */
-#define OPERAND_CMP(p)	(p)[7]
-
-/*
  * Utility definitions.
  */
 #define UCHARAT(p)	((int)*(char_u *)(p))
@@ -345,18 +71,6 @@ toggle_Magic(int x)
 
 #define MAX_LIMIT	(32767L << 16L)
 
-static int cstrncmp(char_u *s1, char_u *s2, int *n);
-static char_u *cstrchr(char_u *, int);
-
-#ifdef BT_REGEXP_DUMP
-static void	regdump(char_u *, bt_regprog_T *);
-#endif
-#ifdef DEBUG
-static char_u	*regprop(char_u *);
-#endif
-
-static int re_mult_next(char *what);
-
 static char_u e_missingbracket[] = N_("E769: Missing ] after %s[");
 static char_u e_reverse_range[] = N_("E944: Reverse range in character class");
 static char_u e_large_class[] = N_("E945: Range too large in character class");
@@ -374,6 +88,14 @@ static char_u e_recursive[]  = N_("E956:
 #define NOT_MULTI	0
 #define MULTI_ONE	1
 #define MULTI_MULT	2
+
+// return values for regmatch()
+#define RA_FAIL		1	/* something failed, abort */
+#define RA_CONT		2	/* continue in inner loop */
+#define RA_BREAK	3	/* break inner loop */
+#define RA_MATCH	4	/* successful match */
+#define RA_NOMATCH	5	/* didn't match */
+
 /*
  * Return NOT_MULTI if c is not a "multi" operator.
  * Return MULTI_ONE if c is a single "multi" operator.
@@ -389,22 +111,6 @@ re_multi_type(int c)
     return NOT_MULTI;
 }
 
-/*
- * Flags to be passed up and down.
- */
-#define HASWIDTH	0x1	/* Known never to match null string. */
-#define SIMPLE		0x2	/* Simple enough to be STAR/PLUS operand. */
-#define SPSTART		0x4	/* Starts with * or +. */
-#define HASNL		0x8	/* Contains some \n. */
-#define HASLOOKBH	0x10	/* Contains "\@<=" or "\@<!". */
-#define WORST		0	/* Worst case. */
-
-/*
- * When regcode is set to this value, code is not emitted and size is computed
- * instead.
- */
-#define JUST_CALC_SIZE	((char_u *) -1)
-
 static char_u		*reg_prev_sub = NULL;
 
 /*
@@ -587,25 +293,15 @@ init_class_tab(void)
  */
 
 static char_u	*regparse;	/* Input-scan pointer. */
-static int	prevchr_len;	/* byte length of previous char */
-static int	num_complex_braces; /* Complex \{...} count */
 static int	regnpar;	/* () count. */
 #ifdef FEAT_SYN_HL
 static int	regnzpar;	/* \z() count. */
 static int	re_has_z;	/* \z item detected */
 #endif
-static char_u	*regcode;	/* Code-emit pointer, or JUST_CALC_SIZE */
-static long	regsize;	/* Code size. */
-static int	reg_toolong;	/* TRUE when offset out of range */
-static char_u	had_endbrace[NSUBEXP];	/* flags, TRUE if end of () found */
 static unsigned	regflags;	/* RF_ flags for prog */
-static long	brace_min[10];	/* Minimums for complex brace repeats */
-static long	brace_max[10];	/* Maximums for complex brace repeats */
-static int	brace_count[10]; /* Current counts for complex brace repeats */
 #if defined(FEAT_SYN_HL) || defined(PROTO)
 static int	had_eol;	/* TRUE when EOL found by vim_regcomp() */
 #endif
-static int	one_exactly = FALSE;	/* only do one char for EXACTLY */
 
 static int	reg_magic;	/* magicness of the pattern: */
 #define MAGIC_NONE	1	/* "\V" very unmagic */
@@ -670,9 +366,6 @@ typedef struct
      int	regnpar;
 } parse_state_T;
 
-/*
- * Forward declarations for vim_regcomp()'s friends.
- */
 static void	initchr(char_u *);
 static int	getchr(void);
 static void	skipchr_keepstart(void);
@@ -683,27 +376,10 @@ static long	gethexchrs(int maxinputlen);
 static long	getoctchrs(void);
 static long	getdecchrs(void);
 static int	coll_get_char(void);
-static void	regcomp_start(char_u *expr, int flags);
-static char_u	*reg(int, int *);
-static char_u	*regbranch(int *flagp);
-static char_u	*regconcat(int *flagp);
-static char_u	*regpiece(int *);
-static char_u	*regatom(int *);
-static char_u	*regnode(int);
-static int	use_multibytecode(int c);
 static int	prog_magic_wrong(void);
-static char_u	*regnext(char_u *);
-static void	regc(int b);
-static void	regmbc(int c);
-#define REGMBC(x) regmbc(x);
-#define CASEMBC(x) case x:
-static void	reginsert(int, char_u *);
-static void	reginsert_nr(int op, long val, char_u *opnd);
-static void	reginsert_limits(int, long, long, char_u *);
-static char_u	*re_put_long(char_u *pr, long_u val);
-static int	read_limits(long *, long *);
-static void	regtail(char_u *, char_u *);
-static void	regoptail(char_u *, char_u *);
+static int	cstrncmp(char_u *s1, char_u *s2, int *n);
+static char_u	*cstrchr(char_u *, int);
+static int	re_mult_next(char *what);
 static int	reg_iswordc(int);
 
 static regengine_T bt_regengine;
@@ -772,333 +448,6 @@ static char *EQUIVAL_CLASS_C[16] = {
 #endif
 
 /*
- * Produce the bytes for equivalence class "c".
- * Currently only handles latin1, latin9 and utf-8.
- * NOTE: When changing this function, also change nfa_emit_equi_class()
- */
-    static void
-reg_equi_class(int c)
-{
-    if (enc_utf8 || STRCMP(p_enc, "latin1") == 0
-					 || STRCMP(p_enc, "iso-8859-15") == 0)
-    {
-#ifdef EBCDIC
-	int i;
-
-	/* This might be slower than switch/case below. */
-	for (i = 0; i < 16; i++)
-	{
-	    if (vim_strchr(EQUIVAL_CLASS_C[i], c) != NULL)
-	    {
-		char *p = EQUIVAL_CLASS_C[i];
-
-		while (*p != 0)
-		    regmbc(*p++);
-		return;
-	    }
-	}
-#else
-	switch (c)
-	{
-	    /* Do not use '\300' style, it results in a negative number. */
-	    case 'A': case 0xc0: case 0xc1: case 0xc2:
-	    case 0xc3: case 0xc4: case 0xc5:
-	    CASEMBC(0x100) CASEMBC(0x102) CASEMBC(0x104) CASEMBC(0x1cd)
-	    CASEMBC(0x1de) CASEMBC(0x1e0) CASEMBC(0x1ea2)
-		      regmbc('A'); regmbc(0xc0); regmbc(0xc1);
-		      regmbc(0xc2); regmbc(0xc3); regmbc(0xc4);
-		      regmbc(0xc5);
-		      REGMBC(0x100) REGMBC(0x102) REGMBC(0x104)
-		      REGMBC(0x1cd) REGMBC(0x1de) REGMBC(0x1e0)
-		      REGMBC(0x1ea2)
-		      return;
-	    case 'B': CASEMBC(0x1e02) CASEMBC(0x1e06)
-		      regmbc('B'); REGMBC(0x1e02) REGMBC(0x1e06)
-		      return;
-	    case 'C': case 0xc7:
-	    CASEMBC(0x106) CASEMBC(0x108) CASEMBC(0x10a) CASEMBC(0x10c)
-		      regmbc('C'); regmbc(0xc7);
-		      REGMBC(0x106) REGMBC(0x108) REGMBC(0x10a)
-		      REGMBC(0x10c)
-		      return;
-	    case 'D': CASEMBC(0x10e) CASEMBC(0x110) CASEMBC(0x1e0a)
-	    CASEMBC(0x1e0e) CASEMBC(0x1e10)
-		      regmbc('D'); REGMBC(0x10e) REGMBC(0x110)
-		      REGMBC(0x1e0a) REGMBC(0x1e0e) REGMBC(0x1e10)
-		      return;
-	    case 'E': case 0xc8: case 0xc9: case 0xca: case 0xcb:
-	    CASEMBC(0x112) CASEMBC(0x114) CASEMBC(0x116) CASEMBC(0x118)
-	    CASEMBC(0x11a) CASEMBC(0x1eba) CASEMBC(0x1ebc)
-		      regmbc('E'); regmbc(0xc8); regmbc(0xc9);
-		      regmbc(0xca); regmbc(0xcb);
-		      REGMBC(0x112) REGMBC(0x114) REGMBC(0x116)
-		      REGMBC(0x118) REGMBC(0x11a) REGMBC(0x1eba)
-		      REGMBC(0x1ebc)
-		      return;
-	    case 'F': CASEMBC(0x1e1e)
-		      regmbc('F'); REGMBC(0x1e1e)
-		      return;
-	    case 'G': CASEMBC(0x11c) CASEMBC(0x11e) CASEMBC(0x120)
-	    CASEMBC(0x122) CASEMBC(0x1e4) CASEMBC(0x1e6) CASEMBC(0x1f4)
-	    CASEMBC(0x1e20)
-		      regmbc('G'); REGMBC(0x11c) REGMBC(0x11e)
-		      REGMBC(0x120) REGMBC(0x122) REGMBC(0x1e4)
-		      REGMBC(0x1e6) REGMBC(0x1f4) REGMBC(0x1e20)
-		      return;
-	    case 'H': CASEMBC(0x124) CASEMBC(0x126) CASEMBC(0x1e22)
-	    CASEMBC(0x1e26) CASEMBC(0x1e28)
-		      regmbc('H'); REGMBC(0x124) REGMBC(0x126)
-		      REGMBC(0x1e22) REGMBC(0x1e26) REGMBC(0x1e28)
-		      return;
-	    case 'I': case 0xcc: case 0xcd: case 0xce: case 0xcf:
-	    CASEMBC(0x128) CASEMBC(0x12a) CASEMBC(0x12c) CASEMBC(0x12e)
-	    CASEMBC(0x130) CASEMBC(0x1cf) CASEMBC(0x1ec8)
-		      regmbc('I'); regmbc(0xcc); regmbc(0xcd);
-		      regmbc(0xce); regmbc(0xcf);
-		      REGMBC(0x128) REGMBC(0x12a) REGMBC(0x12c)
-		      REGMBC(0x12e) REGMBC(0x130) REGMBC(0x1cf)
-		      REGMBC(0x1ec8)
-		      return;
-	    case 'J': CASEMBC(0x134)
-		      regmbc('J'); REGMBC(0x134)
-		      return;
-	    case 'K': CASEMBC(0x136) CASEMBC(0x1e8) CASEMBC(0x1e30)
-	    CASEMBC(0x1e34)
-		      regmbc('K'); REGMBC(0x136) REGMBC(0x1e8)
-		      REGMBC(0x1e30) REGMBC(0x1e34)
-		      return;
-	    case 'L': CASEMBC(0x139) CASEMBC(0x13b) CASEMBC(0x13d)
-	    CASEMBC(0x13f) CASEMBC(0x141) CASEMBC(0x1e3a)
-		      regmbc('L'); REGMBC(0x139) REGMBC(0x13b)
-		      REGMBC(0x13d) REGMBC(0x13f) REGMBC(0x141)
-		      REGMBC(0x1e3a)
-		      return;
-	    case 'M': CASEMBC(0x1e3e) CASEMBC(0x1e40)
-		      regmbc('M'); REGMBC(0x1e3e) REGMBC(0x1e40)
-		      return;
-	    case 'N': case 0xd1:
-	    CASEMBC(0x143) CASEMBC(0x145) CASEMBC(0x147) CASEMBC(0x1e44)
-	    CASEMBC(0x1e48)
-		      regmbc('N'); regmbc(0xd1);
-		      REGMBC(0x143) REGMBC(0x145) REGMBC(0x147)
-		      REGMBC(0x1e44) REGMBC(0x1e48)
-		      return;
-	    case 'O': case 0xd2: case 0xd3: case 0xd4: case 0xd5:
-	    case 0xd6: case 0xd8:
-	    CASEMBC(0x14c) CASEMBC(0x14e) CASEMBC(0x150) CASEMBC(0x1a0)
-	    CASEMBC(0x1d1) CASEMBC(0x1ea) CASEMBC(0x1ec) CASEMBC(0x1ece)
-		      regmbc('O'); regmbc(0xd2); regmbc(0xd3);
-		      regmbc(0xd4); regmbc(0xd5); regmbc(0xd6);
-		      regmbc(0xd8);
-		      REGMBC(0x14c) REGMBC(0x14e) REGMBC(0x150)
-		      REGMBC(0x1a0) REGMBC(0x1d1) REGMBC(0x1ea)
-		      REGMBC(0x1ec) REGMBC(0x1ece)
-		      return;
-	    case 'P': case 0x1e54: case 0x1e56:
-		      regmbc('P'); REGMBC(0x1e54) REGMBC(0x1e56)
-		      return;
-	    case 'R': CASEMBC(0x154) CASEMBC(0x156) CASEMBC(0x158)
-	    CASEMBC(0x1e58) CASEMBC(0x1e5e)
-		      regmbc('R'); REGMBC(0x154) REGMBC(0x156) REGMBC(0x158)
-		      REGMBC(0x1e58) REGMBC(0x1e5e)
-		      return;
-	    case 'S': CASEMBC(0x15a) CASEMBC(0x15c) CASEMBC(0x15e)
-	    CASEMBC(0x160) CASEMBC(0x1e60)
-		      regmbc('S'); REGMBC(0x15a) REGMBC(0x15c)
-		      REGMBC(0x15e) REGMBC(0x160) REGMBC(0x1e60)
-		      return;
-	    case 'T': CASEMBC(0x162) CASEMBC(0x164) CASEMBC(0x166)
-	    CASEMBC(0x1e6a) CASEMBC(0x1e6e)
-		      regmbc('T'); REGMBC(0x162) REGMBC(0x164)
-		      REGMBC(0x166) REGMBC(0x1e6a) REGMBC(0x1e6e)
-		      return;
-	    case 'U': case 0xd9: case 0xda: case 0xdb: case 0xdc:
-	    CASEMBC(0x168) CASEMBC(0x16a) CASEMBC(0x16c) CASEMBC(0x16e)
-	    CASEMBC(0x170) CASEMBC(0x172) CASEMBC(0x1af) CASEMBC(0x1d3)
-	    CASEMBC(0x1ee6)
-		      regmbc('U'); regmbc(0xd9); regmbc(0xda);
-		      regmbc(0xdb); regmbc(0xdc);
-		      REGMBC(0x168) REGMBC(0x16a) REGMBC(0x16c)
-		      REGMBC(0x16e) REGMBC(0x170) REGMBC(0x172)
-		      REGMBC(0x1af) REGMBC(0x1d3) REGMBC(0x1ee6)
-		      return;
-	    case 'V': CASEMBC(0x1e7c)
-		      regmbc('V'); REGMBC(0x1e7c)
-		      return;
-	    case 'W': CASEMBC(0x174) CASEMBC(0x1e80) CASEMBC(0x1e82)
-	    CASEMBC(0x1e84) CASEMBC(0x1e86)
-		      regmbc('W'); REGMBC(0x174) REGMBC(0x1e80)
-		      REGMBC(0x1e82) REGMBC(0x1e84) REGMBC(0x1e86)
-		      return;
-	    case 'X': CASEMBC(0x1e8a) CASEMBC(0x1e8c)
-		      regmbc('X'); REGMBC(0x1e8a) REGMBC(0x1e8c)
-		      return;
-	    case 'Y': case 0xdd:
-	    CASEMBC(0x176) CASEMBC(0x178) CASEMBC(0x1e8e) CASEMBC(0x1ef2)
-	    CASEMBC(0x1ef6) CASEMBC(0x1ef8)
-		      regmbc('Y'); regmbc(0xdd);
-		      REGMBC(0x176) REGMBC(0x178) REGMBC(0x1e8e)
-		      REGMBC(0x1ef2) REGMBC(0x1ef6) REGMBC(0x1ef8)
-		      return;
-	    case 'Z': CASEMBC(0x179) CASEMBC(0x17b) CASEMBC(0x17d)
-	    CASEMBC(0x1b5) CASEMBC(0x1e90) CASEMBC(0x1e94)
-		      regmbc('Z'); REGMBC(0x179) REGMBC(0x17b)
-		      REGMBC(0x17d) REGMBC(0x1b5) REGMBC(0x1e90)
-		      REGMBC(0x1e94)
-		      return;
-	    case 'a': case 0xe0: case 0xe1: case 0xe2:
-	    case 0xe3: case 0xe4: case 0xe5:
-	    CASEMBC(0x101) CASEMBC(0x103) CASEMBC(0x105) CASEMBC(0x1ce)
-	    CASEMBC(0x1df) CASEMBC(0x1e1) CASEMBC(0x1ea3)
-		      regmbc('a'); regmbc(0xe0); regmbc(0xe1);
-		      regmbc(0xe2); regmbc(0xe3); regmbc(0xe4);
-		      regmbc(0xe5);
-		      REGMBC(0x101) REGMBC(0x103) REGMBC(0x105)
-		      REGMBC(0x1ce) REGMBC(0x1df) REGMBC(0x1e1)
-		      REGMBC(0x1ea3)
-		      return;
-	    case 'b': CASEMBC(0x1e03) CASEMBC(0x1e07)
-		      regmbc('b'); REGMBC(0x1e03) REGMBC(0x1e07)
-		      return;
-	    case 'c': case 0xe7:
-	    CASEMBC(0x107) CASEMBC(0x109) CASEMBC(0x10b) CASEMBC(0x10d)
-		      regmbc('c'); regmbc(0xe7);
-		      REGMBC(0x107) REGMBC(0x109) REGMBC(0x10b)
-		      REGMBC(0x10d)
-		      return;
-	    case 'd': CASEMBC(0x10f) CASEMBC(0x111) CASEMBC(0x1e0b)
-	    CASEMBC(0x1e0f) CASEMBC(0x1e11)
-		      regmbc('d'); REGMBC(0x10f) REGMBC(0x111)
-		      REGMBC(0x1e0b) REGMBC(0x1e0f) REGMBC(0x1e11)
-		      return;
-	    case 'e': case 0xe8: case 0xe9: case 0xea: case 0xeb:
-	    CASEMBC(0x113) CASEMBC(0x115) CASEMBC(0x117) CASEMBC(0x119)
-	    CASEMBC(0x11b) CASEMBC(0x1ebb) CASEMBC(0x1ebd)
-		      regmbc('e'); regmbc(0xe8); regmbc(0xe9);
-		      regmbc(0xea); regmbc(0xeb);
-		      REGMBC(0x113) REGMBC(0x115) REGMBC(0x117)
-		      REGMBC(0x119) REGMBC(0x11b) REGMBC(0x1ebb)
-		      REGMBC(0x1ebd)
-		      return;
-	    case 'f': CASEMBC(0x1e1f)
-		      regmbc('f'); REGMBC(0x1e1f)
-		      return;
-	    case 'g': CASEMBC(0x11d) CASEMBC(0x11f) CASEMBC(0x121)
-	    CASEMBC(0x123) CASEMBC(0x1e5) CASEMBC(0x1e7) CASEMBC(0x1f5)
-	    CASEMBC(0x1e21)
-		      regmbc('g'); REGMBC(0x11d) REGMBC(0x11f)
-		      REGMBC(0x121) REGMBC(0x123) REGMBC(0x1e5)
-		      REGMBC(0x1e7) REGMBC(0x1f5) REGMBC(0x1e21)
-		      return;
-	    case 'h': CASEMBC(0x125) CASEMBC(0x127) CASEMBC(0x1e23)
-	    CASEMBC(0x1e27) CASEMBC(0x1e29) CASEMBC(0x1e96)
-		      regmbc('h'); REGMBC(0x125) REGMBC(0x127)
-		      REGMBC(0x1e23) REGMBC(0x1e27) REGMBC(0x1e29)
-		      REGMBC(0x1e96)
-		      return;
-	    case 'i': case 0xec: case 0xed: case 0xee: case 0xef:
-	    CASEMBC(0x129) CASEMBC(0x12b) CASEMBC(0x12d) CASEMBC(0x12f)
-	    CASEMBC(0x1d0) CASEMBC(0x1ec9)
-		      regmbc('i'); regmbc(0xec); regmbc(0xed);
-		      regmbc(0xee); regmbc(0xef);
-		      REGMBC(0x129) REGMBC(0x12b) REGMBC(0x12d)
-		      REGMBC(0x12f) REGMBC(0x1d0) REGMBC(0x1ec9)
-		      return;
-	    case 'j': CASEMBC(0x135) CASEMBC(0x1f0)
-		      regmbc('j'); REGMBC(0x135) REGMBC(0x1f0)
-		      return;
-	    case 'k': CASEMBC(0x137) CASEMBC(0x1e9) CASEMBC(0x1e31)
-	    CASEMBC(0x1e35)
-		      regmbc('k'); REGMBC(0x137) REGMBC(0x1e9)
-		      REGMBC(0x1e31) REGMBC(0x1e35)
-		      return;
-	    case 'l': CASEMBC(0x13a) CASEMBC(0x13c) CASEMBC(0x13e)
-	    CASEMBC(0x140) CASEMBC(0x142) CASEMBC(0x1e3b)
-		      regmbc('l'); REGMBC(0x13a) REGMBC(0x13c)
-		      REGMBC(0x13e) REGMBC(0x140) REGMBC(0x142)
-		      REGMBC(0x1e3b)
-		      return;
-	    case 'm': CASEMBC(0x1e3f) CASEMBC(0x1e41)
-		      regmbc('m'); REGMBC(0x1e3f) REGMBC(0x1e41)
-		      return;
-	    case 'n': case 0xf1:
-	    CASEMBC(0x144) CASEMBC(0x146) CASEMBC(0x148) CASEMBC(0x149)
-	    CASEMBC(0x1e45) CASEMBC(0x1e49)
-		      regmbc('n'); regmbc(0xf1);
-		      REGMBC(0x144) REGMBC(0x146) REGMBC(0x148)
-		      REGMBC(0x149) REGMBC(0x1e45) REGMBC(0x1e49)
-		      return;
-	    case 'o': case 0xf2: case 0xf3: case 0xf4: case 0xf5:
-	    case 0xf6: case 0xf8:
-	    CASEMBC(0x14d) CASEMBC(0x14f) CASEMBC(0x151) CASEMBC(0x1a1)
-	    CASEMBC(0x1d2) CASEMBC(0x1eb) CASEMBC(0x1ed) CASEMBC(0x1ecf)
-		      regmbc('o'); regmbc(0xf2); regmbc(0xf3);
-		      regmbc(0xf4); regmbc(0xf5); regmbc(0xf6);
-		      regmbc(0xf8);
-		      REGMBC(0x14d) REGMBC(0x14f) REGMBC(0x151)
-		      REGMBC(0x1a1) REGMBC(0x1d2) REGMBC(0x1eb)
-		      REGMBC(0x1ed) REGMBC(0x1ecf)
-		      return;
-	    case 'p': CASEMBC(0x1e55) CASEMBC(0x1e57)
-		      regmbc('p'); REGMBC(0x1e55) REGMBC(0x1e57)
-		      return;
-	    case 'r': CASEMBC(0x155) CASEMBC(0x157) CASEMBC(0x159)
-	    CASEMBC(0x1e59) CASEMBC(0x1e5f)
-		      regmbc('r'); REGMBC(0x155) REGMBC(0x157) REGMBC(0x159)
-		      REGMBC(0x1e59) REGMBC(0x1e5f)
-		      return;
-	    case 's': CASEMBC(0x15b) CASEMBC(0x15d) CASEMBC(0x15f)
-	    CASEMBC(0x161) CASEMBC(0x1e61)
-		      regmbc('s'); REGMBC(0x15b) REGMBC(0x15d)
-		      REGMBC(0x15f) REGMBC(0x161) REGMBC(0x1e61)
-		      return;
-	    case 't': CASEMBC(0x163) CASEMBC(0x165) CASEMBC(0x167)
-	    CASEMBC(0x1e6b) CASEMBC(0x1e6f) CASEMBC(0x1e97)
-		      regmbc('t'); REGMBC(0x163) REGMBC(0x165) REGMBC(0x167)
-		      REGMBC(0x1e6b) REGMBC(0x1e6f) REGMBC(0x1e97)
-		      return;
-	    case 'u': case 0xf9: case 0xfa: case 0xfb: case 0xfc:
-	    CASEMBC(0x169) CASEMBC(0x16b) CASEMBC(0x16d) CASEMBC(0x16f)
-	    CASEMBC(0x171) CASEMBC(0x173) CASEMBC(0x1b0) CASEMBC(0x1d4)
-	    CASEMBC(0x1ee7)
-		      regmbc('u'); regmbc(0xf9); regmbc(0xfa);
-		      regmbc(0xfb); regmbc(0xfc);
-		      REGMBC(0x169) REGMBC(0x16b) REGMBC(0x16d)
-		      REGMBC(0x16f) REGMBC(0x171) REGMBC(0x173)
-		      REGMBC(0x1b0) REGMBC(0x1d4) REGMBC(0x1ee7)
-		      return;
-	    case 'v': CASEMBC(0x1e7d)
-		      regmbc('v'); REGMBC(0x1e7d)
-		      return;
-	    case 'w': CASEMBC(0x175) CASEMBC(0x1e81) CASEMBC(0x1e83)
-	    CASEMBC(0x1e85) CASEMBC(0x1e87) CASEMBC(0x1e98)
-		      regmbc('w'); REGMBC(0x175) REGMBC(0x1e81)
-		      REGMBC(0x1e83) REGMBC(0x1e85) REGMBC(0x1e87)
-		      REGMBC(0x1e98)
-		      return;
-	    case 'x': CASEMBC(0x1e8b) CASEMBC(0x1e8d)
-		      regmbc('x'); REGMBC(0x1e8b) REGMBC(0x1e8d)
-		      return;
-	    case 'y': case 0xfd: case 0xff:
-	    CASEMBC(0x177) CASEMBC(0x1e8f) CASEMBC(0x1e99)
-	    CASEMBC(0x1ef3) CASEMBC(0x1ef7) CASEMBC(0x1ef9)
-		      regmbc('y'); regmbc(0xfd); regmbc(0xff);
-		      REGMBC(0x177) REGMBC(0x1e8f) REGMBC(0x1e99)
-		      REGMBC(0x1ef3) REGMBC(0x1ef7) REGMBC(0x1ef9)
-		      return;
-	    case 'z': CASEMBC(0x17a) CASEMBC(0x17c) CASEMBC(0x17e)
-	    CASEMBC(0x1b6) CASEMBC(0x1e91) CASEMBC(0x1e95)
-		      regmbc('z'); REGMBC(0x17a) REGMBC(0x17c)
-		      REGMBC(0x17e) REGMBC(0x1b6) REGMBC(0x1e91)
-		      REGMBC(0x1e95)
-		      return;
-	}
-#endif
-    }
-    regmbc(c);
-}
-
-/*
  * Check for a collating element "[.a.]".  "pp" points to the '['.
  * Returns a character. Zero means that no item was recognized.  Otherwise
  * "pp" is advanced to after the item.
@@ -1247,1660 +596,13 @@ skip_regexp(
 }
 
 /*
- * Return TRUE if the back reference is legal. We must have seen the close
- * brace.
- * TODO: Should also check that we don't refer to something that is repeated
- * (+*=): what instance of the repetition should we match?
- */
-    static int
-seen_endbrace(int refnum)
-{
-    if (!had_endbrace[refnum])
-    {
-	char_u *p;
-
-	/* Trick: check if "@<=" or "@<!" follows, in which case
-	 * the \1 can appear before the referenced match. */
-	for (p = regparse; *p != NUL; ++p)
-	    if (p[0] == '@' && p[1] == '<' && (p[2] == '!' || p[2] == '='))
-		break;
-	if (*p == NUL)
-	{
-	    emsg(_("E65: Illegal back reference"));
-	    rc_did_emsg = TRUE;
-	    return FALSE;
-	}
-    }
-    return TRUE;
-}
-
-/*
- * bt_regcomp() - compile a regular expression into internal code for the
- * traditional back track matcher.
- * Returns the program in allocated space.  Returns NULL for an error.
- *
- * We can't allocate space until we know how big the compiled form will be,
- * but we can't compile it (and thus know how big it is) until we've got a
- * place to put the code.  So we cheat:  we compile it twice, once with code
- * generation turned off and size counting turned on, and once "for real".
- * This also means that we don't allocate space until we are sure that the
- * thing really will compile successfully, and we never have to move the
- * code and thus invalidate pointers into it.  (Note that it has to be in
- * one piece because vim_free() must be able to free it all.)
- *
- * Whether upper/lower case is to be ignored is decided when executing the
- * program, it does not matter here.
- *
- * Beware that the optimization-preparation code in here knows about some
- * of the structure of the compiled regexp.
- * "re_flags": RE_MAGIC and/or RE_STRING.
+ * Functions for getting characters from the regexp input.
  */
-    static regprog_T *
-bt_regcomp(char_u *expr, int re_flags)
-{
-    bt_regprog_T    *r;
-    char_u	*scan;
-    char_u	*longest;
-    int		len;
-    int		flags;
-
-    if (expr == NULL)
-	EMSG_RET_NULL(_(e_null));
-
-    init_class_tab();
-
-    /*
-     * First pass: determine size, legality.
-     */
-    regcomp_start(expr, re_flags);
-    regcode = JUST_CALC_SIZE;
-    regc(REGMAGIC);
-    if (reg(REG_NOPAREN, &flags) == NULL)
-	return NULL;
-
-    /* Allocate space. */
-    r = alloc(offsetof(bt_regprog_T, program) + regsize);
-    if (r == NULL)
-	return NULL;
-    r->re_in_use = FALSE;
-
-    /*
-     * Second pass: emit code.
-     */
-    regcomp_start(expr, re_flags);
-    regcode = r->program;
-    regc(REGMAGIC);
-    if (reg(REG_NOPAREN, &flags) == NULL || reg_toolong)
-    {
-	vim_free(r);
-	if (reg_toolong)
-	    EMSG_RET_NULL(_("E339: Pattern too long"));
-	return NULL;
-    }
-
-    /* Dig out information for optimizations. */
-    r->regstart = NUL;		/* Worst-case defaults. */
-    r->reganch = 0;
-    r->regmust = NULL;
-    r->regmlen = 0;
-    r->regflags = regflags;
-    if (flags & HASNL)
-	r->regflags |= RF_HASNL;
-    if (flags & HASLOOKBH)
-	r->regflags |= RF_LOOKBH;
-#ifdef FEAT_SYN_HL
-    /* Remember whether this pattern has any \z specials in it. */
-    r->reghasz = re_has_z;
-#endif
-    scan = r->program + 1;	/* First BRANCH. */
-    if (OP(regnext(scan)) == END)   /* Only one top-level choice. */
-    {
-	scan = OPERAND(scan);
-
-	/* Starting-point info. */
-	if (OP(scan) == BOL || OP(scan) == RE_BOF)
-	{
-	    r->reganch++;
-	    scan = regnext(scan);
-	}
-
-	if (OP(scan) == EXACTLY)
-	{
-	    if (has_mbyte)
-		r->regstart = (*mb_ptr2char)(OPERAND(scan));
-	    else
-		r->regstart = *OPERAND(scan);
-	}
-	else if ((OP(scan) == BOW
-		    || OP(scan) == EOW
-		    || OP(scan) == NOTHING
-		    || OP(scan) == MOPEN + 0 || OP(scan) == NOPEN
-		    || OP(scan) == MCLOSE + 0 || OP(scan) == NCLOSE)
-		 && OP(regnext(scan)) == EXACTLY)
-	{
-	    if (has_mbyte)
-		r->regstart = (*mb_ptr2char)(OPERAND(regnext(scan)));
-	    else
-		r->regstart = *OPERAND(regnext(scan));
-	}
-
-	/*
-	 * If there's something expensive in the r.e., find the longest
-	 * literal string that must appear and make it the regmust.  Resolve
-	 * ties in favor of later strings, since the regstart check works
-	 * with the beginning of the r.e. and avoiding duplication
-	 * strengthens checking.  Not a strong reason, but sufficient in the
-	 * absence of others.
-	 */
-	/*
-	 * When the r.e. starts with BOW, it is faster to look for a regmust
-	 * first. Used a lot for "#" and "*" commands. (Added by mool).
-	 */
-	if ((flags & SPSTART || OP(scan) == BOW || OP(scan) == EOW)
-							  && !(flags & HASNL))
-	{
-	    longest = NULL;
-	    len = 0;
-	    for (; scan != NULL; scan = regnext(scan))
-		if (OP(scan) == EXACTLY && STRLEN(OPERAND(scan)) >= (size_t)len)
-		{
-		    longest = OPERAND(scan);
-		    len = (int)STRLEN(OPERAND(scan));
-		}
-	    r->regmust = longest;
-	    r->regmlen = len;
-	}
-    }
-#ifdef BT_REGEXP_DUMP
-    regdump(expr, r);
-#endif
-    r->engine = &bt_regengine;
-    return (regprog_T *)r;
-}
-
-/*
- * Free a compiled regexp program, returned by bt_regcomp().
- */
-    static void
-bt_regfree(regprog_T *prog)
-{
-    vim_free(prog);
-}
-
-/*
- * Setup to parse the regexp.  Used once to get the length and once to do it.
- */
-    static void
-regcomp_start(
-    char_u	*expr,
-    int		re_flags)	    /* see vim_regcomp() */
-{
-    initchr(expr);
-    if (re_flags & RE_MAGIC)
-	reg_magic = MAGIC_ON;
-    else
-	reg_magic = MAGIC_OFF;
-    reg_string = (re_flags & RE_STRING);
-    reg_strict = (re_flags & RE_STRICT);
-    get_cpo_flags();
-
-    num_complex_braces = 0;
-    regnpar = 1;
-    vim_memset(had_endbrace, 0, sizeof(had_endbrace));
-#ifdef FEAT_SYN_HL
-    regnzpar = 1;
-    re_has_z = 0;
-#endif
-    regsize = 0L;
-    reg_toolong = FALSE;
-    regflags = 0;
-#if defined(FEAT_SYN_HL) || defined(PROTO)
-    had_eol = FALSE;
-#endif
-}
-
-#if defined(FEAT_SYN_HL) || defined(PROTO)
-/*
- * Check if during the previous call to vim_regcomp the EOL item "$" has been
- * found.  This is messy, but it works fine.
- */
-    int
-vim_regcomp_had_eol(void)
-{
-    return had_eol;
-}
-#endif
-
-// variables used for parsing
+static int	prevchr_len;	/* byte length of previous char */
 static int	at_start;	// True when on the first character
 static int	prev_at_start;  // True when on the second character
 
 /*
- * Parse regular expression, i.e. main body or parenthesized thing.
- *
- * Caller must absorb opening parenthesis.
- *
- * Combining parenthesis handling with the base level of regular expression
- * is a trifle forced, but the need to tie the tails of the branches to what
- * follows makes it hard to avoid.
- */
-    static char_u *
-reg(
-    int		paren,	/* REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN */
-    int		*flagp)
-{
-    char_u	*ret;
-    char_u	*br;
-    char_u	*ender;
-    int		parno = 0;
-    int		flags;
-
-    *flagp = HASWIDTH;		/* Tentatively. */
-
-#ifdef FEAT_SYN_HL
-    if (paren == REG_ZPAREN)
-    {
-	/* Make a ZOPEN node. */
-	if (regnzpar >= NSUBEXP)
-	    EMSG_RET_NULL(_("E50: Too many \\z("));
-	parno = regnzpar;
-	regnzpar++;
-	ret = regnode(ZOPEN + parno);
-    }
-    else
-#endif
-	if (paren == REG_PAREN)
-    {
-	/* Make a MOPEN node. */
-	if (regnpar >= NSUBEXP)
-	    EMSG2_RET_NULL(_("E51: Too many %s("), reg_magic == MAGIC_ALL);
-	parno = regnpar;
-	++regnpar;
-	ret = regnode(MOPEN + parno);
-    }
-    else if (paren == REG_NPAREN)
-    {
-	/* Make a NOPEN node. */
-	ret = regnode(NOPEN);
-    }
-    else
-	ret = NULL;
-
-    /* Pick up the branches, linking them together. */
-    br = regbranch(&flags);
-    if (br == NULL)
-	return NULL;
-    if (ret != NULL)
-	regtail(ret, br);	/* [MZ]OPEN -> first. */
-    else
-	ret = br;
-    /* If one of the branches can be zero-width, the whole thing can.
-     * If one of the branches has * at start or matches a line-break, the
-     * whole thing can. */
-    if (!(flags & HASWIDTH))
-	*flagp &= ~HASWIDTH;
-    *flagp |= flags & (SPSTART | HASNL | HASLOOKBH);
-    while (peekchr() == Magic('|'))
-    {
-	skipchr();
-	br = regbranch(&flags);
-	if (br == NULL || reg_toolong)
-	    return NULL;
-	regtail(ret, br);	/* BRANCH -> BRANCH. */
-	if (!(flags & HASWIDTH))
-	    *flagp &= ~HASWIDTH;
-	*flagp |= flags & (SPSTART | HASNL | HASLOOKBH);
-    }
-
-    /* Make a closing node, and hook it on the end. */
-    ender = regnode(
-#ifdef FEAT_SYN_HL
-	    paren == REG_ZPAREN ? ZCLOSE + parno :
-#endif
-	    paren == REG_PAREN ? MCLOSE + parno :
-	    paren == REG_NPAREN ? NCLOSE : END);
-    regtail(ret, ender);
-
-    /* Hook the tails of the branches to the closing node. */
-    for (br = ret; br != NULL; br = regnext(br))
-	regoptail(br, ender);
-
-    /* Check for proper termination. */
-    if (paren != REG_NOPAREN && getchr() != Magic(')'))
-    {
-#ifdef FEAT_SYN_HL
-	if (paren == REG_ZPAREN)
-	    EMSG_RET_NULL(_("E52: Unmatched \\z("));
-	else
-#endif
-	    if (paren == REG_NPAREN)
-	    EMSG2_RET_NULL(_(e_unmatchedpp), reg_magic == MAGIC_ALL);
-	else
-	    EMSG2_RET_NULL(_(e_unmatchedp), reg_magic == MAGIC_ALL);
-    }
-    else if (paren == REG_NOPAREN && peekchr() != NUL)
-    {
-	if (curchr == Magic(')'))
-	    EMSG2_RET_NULL(_(e_unmatchedpar), reg_magic == MAGIC_ALL);
-	else
-	    EMSG_RET_NULL(_(e_trailing));	/* "Can't happen". */
-	/* NOTREACHED */
-    }
-    /*
-     * Here we set the flag allowing back references to this set of
-     * parentheses.
-     */
-    if (paren == REG_PAREN)
-	had_endbrace[parno] = TRUE;	/* have seen the close paren */
-    return ret;
-}
-
-/*
- * Parse one alternative of an | operator.
- * Implements the & operator.
- */
-    static char_u *
-regbranch(int *flagp)
-{
-    char_u	*ret;
-    char_u	*chain = NULL;
-    char_u	*latest;
-    int		flags;
-
-    *flagp = WORST | HASNL;		/* Tentatively. */
-
-    ret = regnode(BRANCH);
-    for (;;)
-    {
-	latest = regconcat(&flags);
-	if (latest == NULL)
-	    return NULL;
-	/* If one of the branches has width, the whole thing has.  If one of
-	 * the branches anchors at start-of-line, the whole thing does.
-	 * If one of the branches uses look-behind, the whole thing does. */
-	*flagp |= flags & (HASWIDTH | SPSTART | HASLOOKBH);
-	/* If one of the branches doesn't match a line-break, the whole thing
-	 * doesn't. */
-	*flagp &= ~HASNL | (flags & HASNL);
-	if (chain != NULL)
-	    regtail(chain, latest);
-	if (peekchr() != Magic('&'))
-	    break;
-	skipchr();
-	regtail(latest, regnode(END)); /* operand ends */
-	if (reg_toolong)
-	    break;
-	reginsert(MATCH, latest);
-	chain = latest;
-    }
-
-    return ret;
-}
-
-/*
- * Parse one alternative of an | or & operator.
- * Implements the concatenation operator.
- */
-    static char_u *
-regconcat(int *flagp)
-{
-    char_u	*first = NULL;
-    char_u	*chain = NULL;
-    char_u	*latest;
-    int		flags;
-    int		cont = TRUE;
-
-    *flagp = WORST;		/* Tentatively. */
-
-    while (cont)
-    {
-	switch (peekchr())
-	{
-	    case NUL:
-	    case Magic('|'):
-	    case Magic('&'):
-	    case Magic(')'):
-			    cont = FALSE;
-			    break;
-	    case Magic('Z'):
-			    regflags |= RF_ICOMBINE;
-			    skipchr_keepstart();
-			    break;
-	    case Magic('c'):
-			    regflags |= RF_ICASE;
-			    skipchr_keepstart();
-			    break;
-	    case Magic('C'):
-			    regflags |= RF_NOICASE;
-			    skipchr_keepstart();
-			    break;
-	    case Magic('v'):
-			    reg_magic = MAGIC_ALL;
-			    skipchr_keepstart();
-			    curchr = -1;
-			    break;
-	    case Magic('m'):
-			    reg_magic = MAGIC_ON;
-			    skipchr_keepstart();
-			    curchr = -1;
-			    break;
-	    case Magic('M'):
-			    reg_magic = MAGIC_OFF;
-			    skipchr_keepstart();
-			    curchr = -1;
-			    break;
-	    case Magic('V'):
-			    reg_magic = MAGIC_NONE;
-			    skipchr_keepstart();
-			    curchr = -1;
-			    break;
-	    default:
-			    latest = regpiece(&flags);
-			    if (latest == NULL || reg_toolong)
-				return NULL;
-			    *flagp |= flags & (HASWIDTH | HASNL | HASLOOKBH);
-			    if (chain == NULL)	/* First piece. */
-				*flagp |= flags & SPSTART;
-			    else
-				regtail(chain, latest);
-			    chain = latest;
-			    if (first == NULL)
-				first = latest;
-			    break;
-	}
-    }
-    if (first == NULL)		/* Loop ran zero times. */
-	first = regnode(NOTHING);
-    return first;
-}
-
-/*
- * Parse something followed by possible [*+=].
- *
- * Note that the branching code sequences used for = and the general cases
- * of * and + are somewhat optimized:  they use the same NOTHING node as
- * both the endmarker for their branch list and the body of the last branch.
- * It might seem that this node could be dispensed with entirely, but the
- * endmarker role is not redundant.
- */
-    static char_u *
-regpiece(int *flagp)
-{
-    char_u	    *ret;
-    int		    op;
-    char_u	    *next;
-    int		    flags;
-    long	    minval;
-    long	    maxval;
-
-    ret = regatom(&flags);
-    if (ret == NULL)
-	return NULL;
-
-    op = peekchr();
-    if (re_multi_type(op) == NOT_MULTI)
-    {
-	*flagp = flags;
-	return ret;
-    }
-    /* default flags */
-    *flagp = (WORST | SPSTART | (flags & (HASNL | HASLOOKBH)));
-
-    skipchr();
-    switch (op)
-    {
-	case Magic('*'):
-	    if (flags & SIMPLE)
-		reginsert(STAR, ret);
-	    else
-	    {
-		/* Emit x* as (x&|), where & means "self". */
-		reginsert(BRANCH, ret); /* Either x */
-		regoptail(ret, regnode(BACK));	/* and loop */
-		regoptail(ret, ret);	/* back */
-		regtail(ret, regnode(BRANCH));	/* or */
-		regtail(ret, regnode(NOTHING)); /* null. */
-	    }
-	    break;
-
-	case Magic('+'):
-	    if (flags & SIMPLE)
-		reginsert(PLUS, ret);
-	    else
-	    {
-		/* Emit x+ as x(&|), where & means "self". */
-		next = regnode(BRANCH); /* Either */
-		regtail(ret, next);
-		regtail(regnode(BACK), ret);	/* loop back */
-		regtail(next, regnode(BRANCH)); /* or */
-		regtail(ret, regnode(NOTHING)); /* null. */
-	    }
-	    *flagp = (WORST | HASWIDTH | (flags & (HASNL | HASLOOKBH)));
-	    break;
-
-	case Magic('@'):
-	    {
-		int	lop = END;
-		long	nr;
-
-		nr = getdecchrs();
-		switch (no_Magic(getchr()))
-		{
-		    case '=': lop = MATCH; break;		  /* \@= */
-		    case '!': lop = NOMATCH; break;		  /* \@! */
-		    case '>': lop = SUBPAT; break;		  /* \@> */
-		    case '<': switch (no_Magic(getchr()))
-			      {
-				  case '=': lop = BEHIND; break;   /* \@<= */
-				  case '!': lop = NOBEHIND; break; /* \@<! */
-			      }
-		}
-		if (lop == END)
-		    EMSG2_RET_NULL(_("E59: invalid character after %s@"),
-						      reg_magic == MAGIC_ALL);
-		/* Look behind must match with behind_pos. */
-		if (lop == BEHIND || lop == NOBEHIND)
-		{
-		    regtail(ret, regnode(BHPOS));
-		    *flagp |= HASLOOKBH;
-		}
-		regtail(ret, regnode(END)); /* operand ends */
-		if (lop == BEHIND || lop == NOBEHIND)
-		{
-		    if (nr < 0)
-			nr = 0; /* no limit is same as zero limit */
-		    reginsert_nr(lop, nr, ret);
-		}
-		else
-		    reginsert(lop, ret);
-		break;
-	    }
-
-	case Magic('?'):
-	case Magic('='):
-	    /* Emit x= as (x|) */
-	    reginsert(BRANCH, ret);		/* Either x */
-	    regtail(ret, regnode(BRANCH));	/* or */
-	    next = regnode(NOTHING);		/* null. */
-	    regtail(ret, next);
-	    regoptail(ret, next);
-	    break;
-
-	case Magic('{'):
-	    if (!read_limits(&minval, &maxval))
-		return NULL;
-	    if (flags & SIMPLE)
-	    {
-		reginsert(BRACE_SIMPLE, ret);
-		reginsert_limits(BRACE_LIMITS, minval, maxval, ret);
-	    }
-	    else
-	    {
-		if (num_complex_braces >= 10)
-		    EMSG2_RET_NULL(_("E60: Too many complex %s{...}s"),
-						      reg_magic == MAGIC_ALL);
-		reginsert(BRACE_COMPLEX + num_complex_braces, ret);
-		regoptail(ret, regnode(BACK));
-		regoptail(ret, ret);
-		reginsert_limits(BRACE_LIMITS, minval, maxval, ret);
-		++num_complex_braces;
-	    }
-	    if (minval > 0 && maxval > 0)
-		*flagp = (HASWIDTH | (flags & (HASNL | HASLOOKBH)));
-	    break;
-    }
-    if (re_multi_type(peekchr()) != NOT_MULTI)
-    {
-	// Can't have a multi follow a multi.
-	if (peekchr() == Magic('*'))
-	    EMSG2_RET_NULL(_("E61: Nested %s*"), reg_magic >= MAGIC_ON);
-	EMSG3_RET_NULL(_("E62: Nested %s%c"), reg_magic == MAGIC_ALL,
-							  no_Magic(peekchr()));
-    }
-
-    return ret;
-}
-
-/* When making changes to classchars also change nfa_classcodes. */
-static char_u	*classchars = (char_u *)".iIkKfFpPsSdDxXoOwWhHaAlLuU";
-static int	classcodes[] = {
-    ANY, IDENT, SIDENT, KWORD, SKWORD,
-    FNAME, SFNAME, PRINT, SPRINT,
-    WHITE, NWHITE, DIGIT, NDIGIT,
-    HEX, NHEX, OCTAL, NOCTAL,
-    WORD, NWORD, HEAD, NHEAD,
-    ALPHA, NALPHA, LOWER, NLOWER,
-    UPPER, NUPPER
-};
-
-/*
- * Parse the lowest level.
- *
- * Optimization:  gobbles an entire sequence of ordinary characters so that
- * it can turn them into a single node, which is smaller to store and
- * faster to run.  Don't do this when one_exactly is set.
- */
-    static char_u *
-regatom(int *flagp)
-{
-    char_u	    *ret;
-    int		    flags;
-    int		    c;
-    char_u	    *p;
-    int		    extra = 0;
-    int		    save_prev_at_start = prev_at_start;
-
-    *flagp = WORST;		/* Tentatively. */
-
-    c = getchr();
-    switch (c)
-    {
-      case Magic('^'):
-	ret = regnode(BOL);
-	break;
-
-      case Magic('$'):
-	ret = regnode(EOL);
-#if defined(FEAT_SYN_HL) || defined(PROTO)
-	had_eol = TRUE;
-#endif
-	break;
-
-      case Magic('<'):
-	ret = regnode(BOW);
-	break;
-
-      case Magic('>'):
-	ret = regnode(EOW);
-	break;
-
-      case Magic('_'):
-	c = no_Magic(getchr());
-	if (c == '^')		/* "\_^" is start-of-line */
-	{
-	    ret = regnode(BOL);
-	    break;
-	}
-	if (c == '$')		/* "\_$" is end-of-line */
-	{
-	    ret = regnode(EOL);
-#if defined(FEAT_SYN_HL) || defined(PROTO)
-	    had_eol = TRUE;
-#endif
-	    break;
-	}
-
-	extra = ADD_NL;
-	*flagp |= HASNL;
-
-	/* "\_[" is character range plus newline */
-	if (c == '[')
-	    goto collection;
-
-	/* "\_x" is character class plus newline */
-	/* FALLTHROUGH */
-
-	/*
-	 * Character classes.
-	 */
-      case Magic('.'):
-      case Magic('i'):
-      case Magic('I'):
-      case Magic('k'):
-      case Magic('K'):
-      case Magic('f'):
-      case Magic('F'):
-      case Magic('p'):
-      case Magic('P'):
-      case Magic('s'):
-      case Magic('S'):
-      case Magic('d'):
-      case Magic('D'):
-      case Magic('x'):
-      case Magic('X'):
-      case Magic('o'):
-      case Magic('O'):
-      case Magic('w'):
-      case Magic('W'):
-      case Magic('h'):
-      case Magic('H'):
-      case Magic('a'):
-      case Magic('A'):
-      case Magic('l'):
-      case Magic('L'):
-      case Magic('u'):
-      case Magic('U'):
-	p = vim_strchr(classchars, no_Magic(c));
-	if (p == NULL)
-	    EMSG_RET_NULL(_("E63: invalid use of \\_"));
-
-	/* When '.' is followed by a composing char ignore the dot, so that
-	 * the composing char is matched here. */
-	if (enc_utf8 && c == Magic('.') && utf_iscomposing(peekchr()))
-	{
-	    c = getchr();
-	    goto do_multibyte;
-	}
-	ret = regnode(classcodes[p - classchars] + extra);
-	*flagp |= HASWIDTH | SIMPLE;
-	break;
-
-      case Magic('n'):
-	if (reg_string)
-	{
-	    /* In a string "\n" matches a newline character. */
-	    ret = regnode(EXACTLY);
-	    regc(NL);
-	    regc(NUL);
-	    *flagp |= HASWIDTH | SIMPLE;
-	}
-	else
-	{
-	    /* In buffer text "\n" matches the end of a line. */
-	    ret = regnode(NEWL);
-	    *flagp |= HASWIDTH | HASNL;
-	}
-	break;
-
-      case Magic('('):
-	if (one_exactly)
-	    EMSG_ONE_RET_NULL;
-	ret = reg(REG_PAREN, &flags);
-	if (ret == NULL)
-	    return NULL;
-	*flagp |= flags & (HASWIDTH | SPSTART | HASNL | HASLOOKBH);
-	break;
-
-      case NUL:
-      case Magic('|'):
-      case Magic('&'):
-      case Magic(')'):
-	if (one_exactly)
-	    EMSG_ONE_RET_NULL;
-	IEMSG_RET_NULL(_(e_internal));	/* Supposed to be caught earlier. */
-	/* NOTREACHED */
-
-      case Magic('='):
-      case Magic('?'):
-      case Magic('+'):
-      case Magic('@'):
-      case Magic('{'):
-      case Magic('*'):
-	c = no_Magic(c);
-	EMSG3_RET_NULL(_("E64: %s%c follows nothing"),
-		(c == '*' ? reg_magic >= MAGIC_ON : reg_magic == MAGIC_ALL), c);
-	/* NOTREACHED */
-
-      case Magic('~'):		/* previous substitute pattern */
-	    if (reg_prev_sub != NULL)
-	    {
-		char_u	    *lp;
-
-		ret = regnode(EXACTLY);
-		lp = reg_prev_sub;
-		while (*lp != NUL)
-		    regc(*lp++);
-		regc(NUL);
-		if (*reg_prev_sub != NUL)
-		{
-		    *flagp |= HASWIDTH;
-		    if ((lp - reg_prev_sub) == 1)
-			*flagp |= SIMPLE;
-		}
-	    }
-	    else
-		EMSG_RET_NULL(_(e_nopresub));
-	    break;
-
-      case Magic('1'):
-      case Magic('2'):
-      case Magic('3'):
-      case Magic('4'):
-      case Magic('5'):
-      case Magic('6'):
-      case Magic('7'):
-      case Magic('8'):
-      case Magic('9'):
-	    {
-		int		    refnum;
-
-		refnum = c - Magic('0');
-		if (!seen_endbrace(refnum))
-		    return NULL;
-		ret = regnode(BACKREF + refnum);
-	    }
-	    break;
-
-      case Magic('z'):
-	{
-	    c = no_Magic(getchr());
-	    switch (c)
-	    {
-#ifdef FEAT_SYN_HL
-		case '(': if ((reg_do_extmatch & REX_SET) == 0)
-			      EMSG_RET_NULL(_(e_z_not_allowed));
-			  if (one_exactly)
-			      EMSG_ONE_RET_NULL;
-			  ret = reg(REG_ZPAREN, &flags);
-			  if (ret == NULL)
-			      return NULL;
-			  *flagp |= flags & (HASWIDTH|SPSTART|HASNL|HASLOOKBH);
-			  re_has_z = REX_SET;
-			  break;
-
-		case '1':
-		case '2':
-		case '3':
-		case '4':
-		case '5':
-		case '6':
-		case '7':
-		case '8':
-		case '9': if ((reg_do_extmatch & REX_USE) == 0)
-			      EMSG_RET_NULL(_(e_z1_not_allowed));
-			  ret = regnode(ZREF + c - '0');
-			  re_has_z = REX_USE;
-			  break;
-#endif
-
-		case 's': ret = regnode(MOPEN + 0);
-			  if (re_mult_next("\\zs") == FAIL)
-			      return NULL;
-			  break;
-
-		case 'e': ret = regnode(MCLOSE + 0);
-			  if (re_mult_next("\\ze") == FAIL)
-			      return NULL;
-			  break;
-
-		default:  EMSG_RET_NULL(_("E68: Invalid character after \\z"));
-	    }
-	}
-	break;
-
-      case Magic('%'):
-	{
-	    c = no_Magic(getchr());
-	    switch (c)
-	    {
-		/* () without a back reference */
-		case '(':
-		    if (one_exactly)
-			EMSG_ONE_RET_NULL;
-		    ret = reg(REG_NPAREN, &flags);
-		    if (ret == NULL)
-			return NULL;
-		    *flagp |= flags & (HASWIDTH | SPSTART | HASNL | HASLOOKBH);
-		    break;
-
-		/* Catch \%^ and \%$ regardless of where they appear in the
-		 * pattern -- regardless of whether or not it makes sense. */
-		case '^':
-		    ret = regnode(RE_BOF);
-		    break;
-
-		case '$':
-		    ret = regnode(RE_EOF);
-		    break;
-
-		case '#':
-		    ret = regnode(CURSOR);
-		    break;
-
-		case 'V':
-		    ret = regnode(RE_VISUAL);
-		    break;
-
-		case 'C':
-		    ret = regnode(RE_COMPOSING);
-		    break;
-
-		/* \%[abc]: Emit as a list of branches, all ending at the last
-		 * branch which matches nothing. */
-		case '[':
-			  if (one_exactly)	/* doesn't nest */
-			      EMSG_ONE_RET_NULL;
-			  {
-			      char_u	*lastbranch;
-			      char_u	*lastnode = NULL;
-			      char_u	*br;
-
-			      ret = NULL;
-			      while ((c = getchr()) != ']')
-			      {
-				  if (c == NUL)
-				      EMSG2_RET_NULL(_(e_missing_sb),
-						      reg_magic == MAGIC_ALL);
-				  br = regnode(BRANCH);
-				  if (ret == NULL)
-				      ret = br;
-				  else
-				  {
-				      regtail(lastnode, br);
-				      if (reg_toolong)
-					  return NULL;
-				  }
-
-				  ungetchr();
-				  one_exactly = TRUE;
-				  lastnode = regatom(flagp);
-				  one_exactly = FALSE;
-				  if (lastnode == NULL)
-				      return NULL;
-			      }
-			      if (ret == NULL)
-				  EMSG2_RET_NULL(_(e_empty_sb),
-						      reg_magic == MAGIC_ALL);
-			      lastbranch = regnode(BRANCH);
-			      br = regnode(NOTHING);
-			      if (ret != JUST_CALC_SIZE)
-			      {
-				  regtail(lastnode, br);
-				  regtail(lastbranch, br);
-				  /* connect all branches to the NOTHING
-				   * branch at the end */
-				  for (br = ret; br != lastnode; )
-				  {
-				      if (OP(br) == BRANCH)
-				      {
-					  regtail(br, lastbranch);
-					  if (reg_toolong)
-					      return NULL;
-					  br = OPERAND(br);
-				      }
-				      else
-					  br = regnext(br);
-				  }
-			      }
-			      *flagp &= ~(HASWIDTH | SIMPLE);
-			      break;
-			  }
-
-		case 'd':   /* %d123 decimal */
-		case 'o':   /* %o123 octal */
-		case 'x':   /* %xab hex 2 */
-		case 'u':   /* %uabcd hex 4 */
-		case 'U':   /* %U1234abcd hex 8 */
-			  {
-			      long i;
-
-			      switch (c)
-			      {
-				  case 'd': i = getdecchrs(); break;
-				  case 'o': i = getoctchrs(); break;
-				  case 'x': i = gethexchrs(2); break;
-				  case 'u': i = gethexchrs(4); break;
-				  case 'U': i = gethexchrs(8); break;
-				  default:  i = -1; break;
-			      }
-
-			      if (i < 0 || i > INT_MAX)
-				  EMSG2_RET_NULL(
-					_("E678: Invalid character after %s%%[dxouU]"),
-					reg_magic == MAGIC_ALL);
-			      if (use_multibytecode(i))
-				  ret = regnode(MULTIBYTECODE);
-			      else
-				  ret = regnode(EXACTLY);
-			      if (i == 0)
-				  regc(0x0a);
-			      else
-				  regmbc(i);
-			      regc(NUL);
-			      *flagp |= HASWIDTH;
-			      break;
-			  }
-
-		default:
-			  if (VIM_ISDIGIT(c) || c == '<' || c == '>'
-								 || c == '\'')
-			  {
-			      long_u	n = 0;
-			      int	cmp;
-
-			      cmp = c;
-			      if (cmp == '<' || cmp == '>')
-				  c = getchr();
-			      while (VIM_ISDIGIT(c))
-			      {
-				  n = n * 10 + (c - '0');
-				  c = getchr();
-			      }
-			      if (c == '\'' && n == 0)
-			      {
-				  /* "\%'m", "\%<'m" and "\%>'m": Mark */
-				  c = getchr();
-				  ret = regnode(RE_MARK);
-				  if (ret == JUST_CALC_SIZE)
-				      regsize += 2;
-				  else
-				  {
-				      *regcode++ = c;
-				      *regcode++ = cmp;
-				  }
-				  break;
-			      }
-			      else if (c == 'l' || c == 'c' || c == 'v')
-			      {
-				  if (c == 'l')
-				  {
-				      ret = regnode(RE_LNUM);
-				      if (save_prev_at_start)
-					  at_start = TRUE;
-				  }
-				  else if (c == 'c')
-				      ret = regnode(RE_COL);
-				  else
-				      ret = regnode(RE_VCOL);
-				  if (ret == JUST_CALC_SIZE)
-				      regsize += 5;
-				  else
-				  {
-				      /* put the number and the optional
-				       * comparator after the opcode */
-				      regcode = re_put_long(regcode, n);
-				      *regcode++ = cmp;
-				  }
-				  break;
-			      }
-			  }
-
-			  EMSG2_RET_NULL(_("E71: Invalid character after %s%%"),
-						      reg_magic == MAGIC_ALL);
-	    }
-	}
-	break;
-
-      case Magic('['):
-collection:
-	{
-	    char_u	*lp;
-
-	    /*
-	     * If there is no matching ']', we assume the '[' is a normal
-	     * character.  This makes 'incsearch' and ":help [" work.
-	     */
-	    lp = skip_anyof(regparse);
-	    if (*lp == ']')	/* there is a matching ']' */
-	    {
-		int	startc = -1;	/* > 0 when next '-' is a range */
-		int	endc;
-
-		/*
-		 * In a character class, different parsing rules apply.
-		 * Not even \ is special anymore, nothing is.
-		 */
-		if (*regparse == '^')	    /* Complement of range. */
-		{
-		    ret = regnode(ANYBUT + extra);
-		    regparse++;
-		}
-		else
-		    ret = regnode(ANYOF + extra);
-
-		/* At the start ']' and '-' mean the literal character. */
-		if (*regparse == ']' || *regparse == '-')
-		{
-		    startc = *regparse;
-		    regc(*regparse++);
-		}
-
-		while (*regparse != NUL && *regparse != ']')
-		{
-		    if (*regparse == '-')
-		    {
-			++regparse;
-			/* The '-' is not used for a range at the end and
-			 * after or before a '\n'. */
-			if (*regparse == ']' || *regparse == NUL
-				|| startc == -1
-				|| (regparse[0] == '\\' && regparse[1] == 'n'))
-			{
-			    regc('-');
-			    startc = '-';	/* [--x] is a range */
-			}
-			else
-			{
-			    /* Also accept "a-[.z.]" */
-			    endc = 0;
-			    if (*regparse == '[')
-				endc = get_coll_element(&regparse);
-			    if (endc == 0)
-			    {
-				if (has_mbyte)
-				    endc = mb_ptr2char_adv(&regparse);
-				else
-				    endc = *regparse++;
-			    }
-
-			    /* Handle \o40, \x20 and \u20AC style sequences */
-			    if (endc == '\\' && !reg_cpo_lit && !reg_cpo_bsl)
-				endc = coll_get_char();
-
-			    if (startc > endc)
-				EMSG_RET_NULL(_(e_reverse_range));
-			    if (has_mbyte && ((*mb_char2len)(startc) > 1
-						 || (*mb_char2len)(endc) > 1))
-			    {
-				/* Limit to a range of 256 chars. */
-				if (endc > startc + 256)
-				    EMSG_RET_NULL(_(e_large_class));
-				while (++startc <= endc)
-				    regmbc(startc);
-			    }
-			    else
-			    {
-#ifdef EBCDIC
-				int	alpha_only = FALSE;
-
-				/* for alphabetical range skip the gaps
-				 * 'i'-'j', 'r'-'s', 'I'-'J' and 'R'-'S'.  */
-				if (isalpha(startc) && isalpha(endc))
-				    alpha_only = TRUE;
-#endif
-				while (++startc <= endc)
-#ifdef EBCDIC
-				    if (!alpha_only || isalpha(startc))
-#endif
-					regc(startc);
-			    }
-			    startc = -1;
-			}
-		    }
-		    /*
-		     * Only "\]", "\^", "\]" and "\\" are special in Vi.  Vim
-		     * accepts "\t", "\e", etc., but only when the 'l' flag in
-		     * 'cpoptions' is not included.
-		     * Posix doesn't recognize backslash at all.
-		     */
-		    else if (*regparse == '\\'
-			    && !reg_cpo_bsl
-			    && (vim_strchr(REGEXP_INRANGE, regparse[1]) != NULL
-				|| (!reg_cpo_lit
-				    && vim_strchr(REGEXP_ABBR,
-						       regparse[1]) != NULL)))
-		    {
-			regparse++;
-			if (*regparse == 'n')
-			{
-			    /* '\n' in range: also match NL */
-			    if (ret != JUST_CALC_SIZE)
-			    {
-				/* Using \n inside [^] does not change what
-				 * matches. "[^\n]" is the same as ".". */
-				if (*ret == ANYOF)
-				{
-				    *ret = ANYOF + ADD_NL;
-				    *flagp |= HASNL;
-				}
-				/* else: must have had a \n already */
-			    }
-			    regparse++;
-			    startc = -1;
-			}
-			else if (*regparse == 'd'
-				|| *regparse == 'o'
-				|| *regparse == 'x'
-				|| *regparse == 'u'
-				|| *regparse == 'U')
-			{
-			    startc = coll_get_char();
-			    if (startc == 0)
-				regc(0x0a);
-			    else
-				regmbc(startc);
-			}
-			else
-			{
-			    startc = backslash_trans(*regparse++);
-			    regc(startc);
-			}
-		    }
-		    else if (*regparse == '[')
-		    {
-			int c_class;
-			int cu;
-
-			c_class = get_char_class(&regparse);
-			startc = -1;
-			/* Characters assumed to be 8 bits! */
-			switch (c_class)
-			{
-			    case CLASS_NONE:
-				c_class = get_equi_class(&regparse);
-				if (c_class != 0)
-				{
-				    /* produce equivalence class */
-				    reg_equi_class(c_class);
-				}
-				else if ((c_class =
-					    get_coll_element(&regparse)) != 0)
-				{
-				    /* produce a collating element */
-				    regmbc(c_class);
-				}
-				else
-				{
-				    /* literal '[', allow [[-x] as a range */
-				    startc = *regparse++;
-				    regc(startc);
-				}
-				break;
-			    case CLASS_ALNUM:
-				for (cu = 1; cu < 128; cu++)
-				    if (isalnum(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_ALPHA:
-				for (cu = 1; cu < 128; cu++)
-				    if (isalpha(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_BLANK:
-				regc(' ');
-				regc('\t');
-				break;
-			    case CLASS_CNTRL:
-				for (cu = 1; cu <= 127; cu++)
-				    if (iscntrl(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_DIGIT:
-				for (cu = 1; cu <= 127; cu++)
-				    if (VIM_ISDIGIT(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_GRAPH:
-				for (cu = 1; cu <= 127; cu++)
-				    if (isgraph(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_LOWER:
-				for (cu = 1; cu <= 255; cu++)
-				    if (MB_ISLOWER(cu) && cu != 170
-								 && cu != 186)
-					regmbc(cu);
-				break;
-			    case CLASS_PRINT:
-				for (cu = 1; cu <= 255; cu++)
-				    if (vim_isprintc(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_PUNCT:
-				for (cu = 1; cu < 128; cu++)
-				    if (ispunct(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_SPACE:
-				for (cu = 9; cu <= 13; cu++)
-				    regc(cu);
-				regc(' ');
-				break;
-			    case CLASS_UPPER:
-				for (cu = 1; cu <= 255; cu++)
-				    if (MB_ISUPPER(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_XDIGIT:
-				for (cu = 1; cu <= 255; cu++)
-				    if (vim_isxdigit(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_TAB:
-				regc('\t');
-				break;
-			    case CLASS_RETURN:
-				regc('\r');
-				break;
-			    case CLASS_BACKSPACE:
-				regc('\b');
-				break;
-			    case CLASS_ESCAPE:
-				regc('\033');
-				break;
-			    case CLASS_IDENT:
-				for (cu = 1; cu <= 255; cu++)
-				    if (vim_isIDc(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_KEYWORD:
-				for (cu = 1; cu <= 255; cu++)
-				    if (reg_iswordc(cu))
-					regmbc(cu);
-				break;
-			    case CLASS_FNAME:
-				for (cu = 1; cu <= 255; cu++)
-				    if (vim_isfilec(cu))
-					regmbc(cu);
-				break;
-			}
-		    }
-		    else
-		    {
-			if (has_mbyte)
-			{
-			    int	len;
-
-			    /* produce a multibyte character, including any
-			     * following composing characters */
-			    startc = mb_ptr2char(regparse);
-			    len = (*mb_ptr2len)(regparse);
-			    if (enc_utf8 && utf_char2len(startc) != len)
-				startc = -1;	/* composing chars */
-			    while (--len >= 0)
-				regc(*regparse++);
-			}
-			else
-			{
-			    startc = *regparse++;
-			    regc(startc);
-			}
-		    }
-		}
-		regc(NUL);
-		prevchr_len = 1;	/* last char was the ']' */
-		if (*regparse != ']')
-		    EMSG_RET_NULL(_(e_toomsbra));	/* Cannot happen? */
-		skipchr();	    /* let's be friends with the lexer again */
-		*flagp |= HASWIDTH | SIMPLE;
-		break;
-	    }
-	    else if (reg_strict)
-		EMSG2_RET_NULL(_(e_missingbracket), reg_magic > MAGIC_OFF);
-	}
-	/* FALLTHROUGH */
-
-      default:
-	{
-	    int		len;
-
-	    /* A multi-byte character is handled as a separate atom if it's
-	     * before a multi and when it's a composing char. */
-	    if (use_multibytecode(c))
-	    {
-do_multibyte:
-		ret = regnode(MULTIBYTECODE);
-		regmbc(c);
-		*flagp |= HASWIDTH | SIMPLE;
-		break;
-	    }
-
-	    ret = regnode(EXACTLY);
-
-	    /*
-	     * Append characters as long as:
-	     * - there is no following multi, we then need the character in
-	     *   front of it as a single character operand
-	     * - not running into a Magic character
-	     * - "one_exactly" is not set
-	     * But always emit at least one character.  Might be a Multi,
-	     * e.g., a "[" without matching "]".
-	     */
-	    for (len = 0; c != NUL && (len == 0
-			|| (re_multi_type(peekchr()) == NOT_MULTI
-			    && !one_exactly
-			    && !is_Magic(c))); ++len)
-	    {
-		c = no_Magic(c);
-		if (has_mbyte)
-		{
-		    regmbc(c);
-		    if (enc_utf8)
-		    {
-			int	l;
-
-			/* Need to get composing character too. */
-			for (;;)
-			{
-			    l = utf_ptr2len(regparse);
-			    if (!UTF_COMPOSINGLIKE(regparse, regparse + l))
-				break;
-			    regmbc(utf_ptr2char(regparse));
-			    skipchr();
-			}
-		    }
-		}
-		else
-		    regc(c);
-		c = getchr();
-	    }
-	    ungetchr();
-
-	    regc(NUL);
-	    *flagp |= HASWIDTH;
-	    if (len == 1)
-		*flagp |= SIMPLE;
-	}
-	break;
-    }
-
-    return ret;
-}
-
-/*
- * Return TRUE if MULTIBYTECODE should be used instead of EXACTLY for
- * character "c".
- */
-    static int
-use_multibytecode(int c)
-{
-    return has_mbyte && (*mb_char2len)(c) > 1
-		     && (re_multi_type(peekchr()) != NOT_MULTI
-			     || (enc_utf8 && utf_iscomposing(c)));
-}
-
-/*
- * Emit a node.
- * Return pointer to generated code.
- */
-    static char_u *
-regnode(int op)
-{
-    char_u  *ret;
-
-    ret = regcode;
-    if (ret == JUST_CALC_SIZE)
-	regsize += 3;
-    else
-    {
-	*regcode++ = op;
-	*regcode++ = NUL;		/* Null "next" pointer. */
-	*regcode++ = NUL;
-    }
-    return ret;
-}
-
-/*
- * Emit (if appropriate) a byte of code
- */
-    static void
-regc(int b)
-{
-    if (regcode == JUST_CALC_SIZE)
-	regsize++;
-    else
-	*regcode++ = b;
-}
-
-/*
- * Emit (if appropriate) a multi-byte character of code
- */
-    static void
-regmbc(int c)
-{
-    if (!has_mbyte && c > 0xff)
-	return;
-    if (regcode == JUST_CALC_SIZE)
-	regsize += (*mb_char2len)(c);
-    else
-	regcode += (*mb_char2bytes)(c, regcode);
-}
-
-/*
- * Insert an operator in front of already-emitted operand
- *
- * Means relocating the operand.
- */
-    static void
-reginsert(int op, char_u *opnd)
-{
-    char_u	*src;
-    char_u	*dst;
-    char_u	*place;
-
-    if (regcode == JUST_CALC_SIZE)
-    {
-	regsize += 3;
-	return;
-    }
-    src = regcode;
-    regcode += 3;
-    dst = regcode;
-    while (src > opnd)
-	*--dst = *--src;
-
-    place = opnd;		/* Op node, where operand used to be. */
-    *place++ = op;
-    *place++ = NUL;
-    *place = NUL;
-}
-
-/*
- * Insert an operator in front of already-emitted operand.
- * Add a number to the operator.
- */
-    static void
-reginsert_nr(int op, long val, char_u *opnd)
-{
-    char_u	*src;
-    char_u	*dst;
-    char_u	*place;
-
-    if (regcode == JUST_CALC_SIZE)
-    {
-	regsize += 7;
-	return;
-    }
-    src = regcode;
-    regcode += 7;
-    dst = regcode;
-    while (src > opnd)
-	*--dst = *--src;
-
-    place = opnd;		/* Op node, where operand used to be. */
-    *place++ = op;
-    *place++ = NUL;
-    *place++ = NUL;
-    re_put_long(place, (long_u)val);
-}
-
-/*
- * Insert an operator in front of already-emitted operand.
- * The operator has the given limit values as operands.  Also set next pointer.
- *
- * Means relocating the operand.
- */
-    static void
-reginsert_limits(
-    int		op,
-    long	minval,
-    long	maxval,
-    char_u	*opnd)
-{
-    char_u	*src;
-    char_u	*dst;
-    char_u	*place;
-
-    if (regcode == JUST_CALC_SIZE)
-    {
-	regsize += 11;
-	return;
-    }
-    src = regcode;
-    regcode += 11;
-    dst = regcode;
-    while (src > opnd)
-	*--dst = *--src;
-
-    place = opnd;		/* Op node, where operand used to be. */
-    *place++ = op;
-    *place++ = NUL;
-    *place++ = NUL;
-    place = re_put_long(place, (long_u)minval);
-    place = re_put_long(place, (long_u)maxval);
-    regtail(opnd, place);
-}
-
-/*
- * Write a long as four bytes at "p" and return pointer to the next char.
- */
-    static char_u *
-re_put_long(char_u *p, long_u val)
-{
-    *p++ = (char_u) ((val >> 24) & 0377);
-    *p++ = (char_u) ((val >> 16) & 0377);
-    *p++ = (char_u) ((val >> 8) & 0377);
-    *p++ = (char_u) (val & 0377);
-    return p;
-}
-
-/*
- * Set the next-pointer at the end of a node chain.
- */
-    static void
-regtail(char_u *p, char_u *val)
-{
-    char_u	*scan;
-    char_u	*temp;
-    int		offset;
-
-    if (p == JUST_CALC_SIZE)
-	return;
-
-    /* Find last node. */
-    scan = p;
-    for (;;)
-    {
-	temp = regnext(scan);
-	if (temp == NULL)
-	    break;
-	scan = temp;
-    }
-
-    if (OP(scan) == BACK)
-	offset = (int)(scan - val);
-    else
-	offset = (int)(val - scan);
-    /* When the offset uses more than 16 bits it can no longer fit in the two
-     * bytes available.  Use a global flag to avoid having to check return
-     * values in too many places. */
-    if (offset > 0xffff)
-	reg_toolong = TRUE;
-    else
-    {
-	*(scan + 1) = (char_u) (((unsigned)offset >> 8) & 0377);
-	*(scan + 2) = (char_u) (offset & 0377);
-    }
-}
-
-/*
- * Like regtail, on item after a BRANCH; nop if none.
- */
-    static void
-regoptail(char_u *p, char_u *val)
-{
-    /* When op is neither BRANCH nor BRACE_COMPLEX0-9, it is "operandless" */
-    if (p == NULL || p == JUST_CALC_SIZE
-	    || (OP(p) != BRANCH
-		&& (OP(p) < BRACE_COMPLEX || OP(p) > BRACE_COMPLEX + 9)))
-	return;
-    regtail(OPERAND(p), val);
-}
-
-/*
- * Functions for getting characters from the regexp input.
- */
-/*
  * Start parsing at "str".
  */
     static void
@@ -3283,33 +985,6 @@ getoctchrs(void)
 }
 
 /*
- * Get a number after a backslash that is inside [].
- * When nothing is recognized return a backslash.
- */
-    static int
-coll_get_char(void)
-{
-    long	nr = -1;
-
-    switch (*regparse++)
-    {
-	case 'd': nr = getdecchrs(); break;
-	case 'o': nr = getoctchrs(); break;
-	case 'x': nr = gethexchrs(2); break;
-	case 'u': nr = gethexchrs(4); break;
-	case 'U': nr = gethexchrs(8); break;
-    }
-    if (nr < 0 || nr > INT_MAX)
-    {
-	/* If getting the number fails be backwards compatible: the character
-	 * is a backslash. */
-	--regparse;
-	nr = '\\';
-    }
-    return nr;
-}
-
-/*
  * read_limits - Read two integers to be taken as a minimum and maximum.
  * If the first character is '-', then the range is reversed.
  * Should end with 'end'.  If minval is missing, zero is default, if maxval is
@@ -3369,75 +1044,12 @@ read_limits(long *minval, long *maxval)
  * Global work variables for vim_regexec().
  */
 
-/*
- * Structure used to save the current input state, when it needs to be
- * restored after trying a match.  Used by reg_save() and reg_restore().
- * Also stores the length of "backpos".
- */
-typedef struct
-{
-    union
-    {
-	char_u	*ptr;	/* rex.input pointer, for single-line regexp */
-	lpos_T	pos;	/* rex.input pos, for multi-line regexp */
-    } rs_u;
-    int		rs_len;
-} regsave_T;
-
-/* struct to save start/end pointer/position in for \(\) */
-typedef struct
-{
-    union
-    {
-	char_u	*ptr;
-	lpos_T	pos;
-    } se_u;
-} save_se_T;
-
-/* used for BEHIND and NOBEHIND matching */
-typedef struct regbehind_S
-{
-    regsave_T	save_after;
-    regsave_T	save_behind;
-    int		save_need_clear_subexpr;
-    save_se_T   save_start[NSUBEXP];
-    save_se_T   save_end[NSUBEXP];
-} regbehind_T;
-
-static long	bt_regexec_both(char_u *line, colnr_T col, proftime_T *tm, int *timed_out);
-static long	regtry(bt_regprog_T *prog, colnr_T col, proftime_T *tm, int *timed_out);
 static void	cleanup_subexpr(void);
 #ifdef FEAT_SYN_HL
 static void	cleanup_zsubexpr(void);
 #endif
-static void	save_subexpr(regbehind_T *bp);
-static void	restore_subexpr(regbehind_T *bp);
 static void	reg_nextline(void);
-static void	reg_save(regsave_T *save, garray_T *gap);
-static void	reg_restore(regsave_T *save, garray_T *gap);
-static int	reg_save_equal(regsave_T *save);
-static void	save_se_multi(save_se_T *savep, lpos_T *posp);
-static void	save_se_one(save_se_T *savep, char_u **pp);
-
-/* Save the sub-expressions before attempting a match. */
-#define save_se(savep, posp, pp) \
-    REG_MULTI ? save_se_multi((savep), (posp)) : save_se_one((savep), (pp))
-
-/* After a failed match restore the sub-expressions. */
-#define restore_se(savep, posp, pp) { \
-    if (REG_MULTI) \
-	*(posp) = (savep)->se_u.pos; \
-    else \
-	*(pp) = (savep)->se_u.ptr; }
-
-static int	re_num_cmp(long_u val, char_u *scan);
 static int	match_with_backref(linenr_T start_lnum, colnr_T start_col, linenr_T end_lnum, colnr_T end_col, int *bytelen);
-static int	regmatch(char_u *prog, proftime_T *tm, int *timed_out);
-static int	regrepeat(char_u *p, long maxcount);
-
-#ifdef DEBUG
-static int		regnarrate = 0;
-#endif
 
 /*
  * Sometimes need to save a copy of a line.  Since alloc()/free() is very
@@ -3521,102 +1133,6 @@ typedef struct {
 static regexec_T	rex;
 static int		rex_in_use = FALSE;
 
-
-/* Values for rs_state in regitem_T. */
-typedef enum regstate_E
-{
-    RS_NOPEN = 0	/* NOPEN and NCLOSE */
-    , RS_MOPEN		/* MOPEN + [0-9] */
-    , RS_MCLOSE		/* MCLOSE + [0-9] */
-#ifdef FEAT_SYN_HL
-    , RS_ZOPEN		/* ZOPEN + [0-9] */
-    , RS_ZCLOSE		/* ZCLOSE + [0-9] */
-#endif
-    , RS_BRANCH		/* BRANCH */
-    , RS_BRCPLX_MORE	/* BRACE_COMPLEX and trying one more match */
-    , RS_BRCPLX_LONG	/* BRACE_COMPLEX and trying longest match */
-    , RS_BRCPLX_SHORT	/* BRACE_COMPLEX and trying shortest match */
-    , RS_NOMATCH	/* NOMATCH */
-    , RS_BEHIND1	/* BEHIND / NOBEHIND matching rest */
-    , RS_BEHIND2	/* BEHIND / NOBEHIND matching behind part */
-    , RS_STAR_LONG	/* STAR/PLUS/BRACE_SIMPLE longest match */
-    , RS_STAR_SHORT	/* STAR/PLUS/BRACE_SIMPLE shortest match */
-} regstate_T;
-
-/*
- * When there are alternatives a regstate_T is put on the regstack to remember
- * what we are doing.
- * Before it may be another type of item, depending on rs_state, to remember
- * more things.
- */
-typedef struct regitem_S
-{
-    regstate_T	rs_state;	// what we are doing, one of RS_ above
-    short	rs_no;		// submatch nr or BEHIND/NOBEHIND
-    char_u	*rs_scan;	// current node in program
-    union
-    {
-	save_se_T  sesave;
-	regsave_T  regsave;
-    } rs_un;			// room for saving rex.input
-} regitem_T;
-
-static regitem_T *regstack_push(regstate_T state, char_u *scan);
-static void regstack_pop(char_u **scan);
-
-/* used for STAR, PLUS and BRACE_SIMPLE matching */
-typedef struct regstar_S
-{
-    int		nextb;		/* next byte */
-    int		nextb_ic;	/* next byte reverse case */
-    long	count;
-    long	minval;
-    long	maxval;
-} regstar_T;
-
-/* used to store input position when a BACK was encountered, so that we now if
- * we made any progress since the last time. */
-typedef struct backpos_S
-{
-    char_u	*bp_scan;	/* "scan" where BACK was encountered */
-    regsave_T	bp_pos;		/* last input position */
-} backpos_T;
-
-/*
- * "regstack" and "backpos" are used by regmatch().  They are kept over calls
- * to avoid invoking malloc() and free() often.
- * "regstack" is a stack with regitem_T items, sometimes preceded by regstar_T
- * or regbehind_T.
- * "backpos_T" is a table with backpos_T for BACK
- */
-static garray_T	regstack = {0, 0, 0, 0, NULL};
-static garray_T	backpos = {0, 0, 0, 0, NULL};
-
-/*
- * Both for regstack and backpos tables we use the following strategy of
- * allocation (to reduce malloc/free calls):
- * - Initial size is fairly small.
- * - When needed, the tables are grown bigger (8 times at first, double after
- *   that).
- * - After executing the match we free the memory only if the array has grown.
- *   Thus the memory is kept allocated when it's at the initial size.
- * This makes it fast while not keeping a lot of memory allocated.
- * A three times speed increase was observed when using many simple patterns.
- */
-#define REGSTACK_INITIAL	2048
-#define BACKPOS_INITIAL		64
-
-#if defined(EXITFREE) || defined(PROTO)
-    void
-free_regexp_stuff(void)
-{
-    ga_clear(&regstack);
-    ga_clear(&backpos);
-    vim_free(reg_tofree);
-    vim_free(reg_prev_sub);
-}
-#endif
-
 /*
  * Return TRUE if character 'c' is included in 'iskeyword' option for
  * "reg_buf" buffer.
@@ -3643,8 +1159,6 @@ reg_getline(linenr_T lnum)
     return ml_get_buf(rex.reg_buf, rex.reg_firstlnum + lnum, FALSE);
 }
 
-static regsave_T behind_pos;
-
 #ifdef FEAT_SYN_HL
 static char_u	*reg_startzp[NSUBEXP];	/* Workspace to mark beginning */
 static char_u	*reg_endzp[NSUBEXP];	/*   and end of \z(...\) matches */
@@ -3655,280 +1169,6 @@ static lpos_T	reg_endzpos[NSUBEXP];	/* i
 /* TRUE if using multi-line regexp. */
 #define REG_MULTI	(rex.reg_match == NULL)
 
-/*
- * Match a regexp against a string.
- * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
- * Uses curbuf for line count and 'iskeyword'.
- * if "line_lbr" is TRUE  consider a "\n" in "line" to be a line break.
- *
- * Returns 0 for failure, number of lines contained in the match otherwise.
- */
-    static int
-bt_regexec_nl(
-    regmatch_T	*rmp,
-    char_u	*line,	/* string to match against */
-    colnr_T	col,	/* column to start looking for match */
-    int		line_lbr)
-{
-    rex.reg_match = rmp;
-    rex.reg_mmatch = NULL;
-    rex.reg_maxline = 0;
-    rex.reg_line_lbr = line_lbr;
-    rex.reg_buf = curbuf;
-    rex.reg_win = NULL;
-    rex.reg_ic = rmp->rm_ic;
-    rex.reg_icombine = FALSE;
-    rex.reg_maxcol = 0;
-
-    return bt_regexec_both(line, col, NULL, NULL);
-}
-
-/*
- * Match a regexp against multiple lines.
- * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
- * Uses curbuf for line count and 'iskeyword'.
- *
- * Return zero if there is no match.  Return number of lines contained in the
- * match otherwise.
- */
-    static long
-bt_regexec_multi(
-    regmmatch_T	*rmp,
-    win_T	*win,		/* window in which to search or NULL */
-    buf_T	*buf,		/* buffer in which to search */
-    linenr_T	lnum,		/* nr of line to start looking for match */
-    colnr_T	col,		/* column to start looking for match */
-    proftime_T	*tm,		/* timeout limit or NULL */
-    int		*timed_out)	/* flag set on timeout or NULL */
-{
-    rex.reg_match = NULL;
-    rex.reg_mmatch = rmp;
-    rex.reg_buf = buf;
-    rex.reg_win = win;
-    rex.reg_firstlnum = lnum;
-    rex.reg_maxline = rex.reg_buf->b_ml.ml_line_count - lnum;
-    rex.reg_line_lbr = FALSE;
-    rex.reg_ic = rmp->rmm_ic;
-    rex.reg_icombine = FALSE;
-    rex.reg_maxcol = rmp->rmm_maxcol;
-
-    return bt_regexec_both(NULL, col, tm, timed_out);
-}
-
-/*
- * Match a regexp against a string ("line" points to the string) or multiple
- * lines ("line" is NULL, use reg_getline()).
- * Returns 0 for failure, number of lines contained in the match otherwise.
- */
-    static long
-bt_regexec_both(
-    char_u	*line,
-    colnr_T	col,		/* column to start looking for match */
-    proftime_T	*tm,		/* timeout limit or NULL */
-    int		*timed_out)	/* flag set on timeout or NULL */
-{
-    bt_regprog_T    *prog;
-    char_u	    *s;
-    long	    retval = 0L;
-
-    /* Create "regstack" and "backpos" if they are not allocated yet.
-     * We allocate *_INITIAL amount of bytes first and then set the grow size
-     * to much bigger value to avoid many malloc calls in case of deep regular
-     * expressions.  */
-    if (regstack.ga_data == NULL)
-    {
-	/* Use an item size of 1 byte, since we push different things
-	 * onto the regstack. */
-	ga_init2(&regstack, 1, REGSTACK_INITIAL);
-	(void)ga_grow(&regstack, REGSTACK_INITIAL);
-	regstack.ga_growsize = REGSTACK_INITIAL * 8;
-    }
-
-    if (backpos.ga_data == NULL)
-    {
-	ga_init2(&backpos, sizeof(backpos_T), BACKPOS_INITIAL);
-	(void)ga_grow(&backpos, BACKPOS_INITIAL);
-	backpos.ga_growsize = BACKPOS_INITIAL * 8;
-    }
-
-    if (REG_MULTI)
-    {
-	prog = (bt_regprog_T *)rex.reg_mmatch->regprog;
-	line = reg_getline((linenr_T)0);
-	rex.reg_startpos = rex.reg_mmatch->startpos;
-	rex.reg_endpos = rex.reg_mmatch->endpos;
-    }
-    else
-    {
-	prog = (bt_regprog_T *)rex.reg_match->regprog;
-	rex.reg_startp = rex.reg_match->startp;
-	rex.reg_endp = rex.reg_match->endp;
-    }
-
-    /* Be paranoid... */
-    if (prog == NULL || line == NULL)
-    {
-	emsg(_(e_null));
-	goto theend;
-    }
-
-    /* Check validity of program. */
-    if (prog_magic_wrong())
-	goto theend;
-
-    /* If the start column is past the maximum column: no need to try. */
-    if (rex.reg_maxcol > 0 && col >= rex.reg_maxcol)
-	goto theend;
-
-    /* If pattern contains "\c" or "\C": overrule value of rex.reg_ic */
-    if (prog->regflags & RF_ICASE)
-	rex.reg_ic = TRUE;
-    else if (prog->regflags & RF_NOICASE)
-	rex.reg_ic = FALSE;
-
-    /* If pattern contains "\Z" overrule value of rex.reg_icombine */
-    if (prog->regflags & RF_ICOMBINE)
-	rex.reg_icombine = TRUE;
-
-    /* If there is a "must appear" string, look for it. */
-    if (prog->regmust != NULL)
-    {
-	int c;
-
-	if (has_mbyte)
-	    c = (*mb_ptr2char)(prog->regmust);
-	else
-	    c = *prog->regmust;
-	s = line + col;
-
-	/*
-	 * This is used very often, esp. for ":global".  Use three versions of
-	 * the loop to avoid overhead of conditions.
-	 */
-	if (!rex.reg_ic && !has_mbyte)
-	    while ((s = vim_strbyte(s, c)) != NULL)
-	    {
-		if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0)
-		    break;		/* Found it. */
-		++s;
-	    }
-	else if (!rex.reg_ic || (!enc_utf8 && mb_char2len(c) > 1))
-	    while ((s = vim_strchr(s, c)) != NULL)
-	    {
-		if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0)
-		    break;		/* Found it. */
-		MB_PTR_ADV(s);
-	    }
-	else
-	    while ((s = cstrchr(s, c)) != NULL)
-	    {
-		if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0)
-		    break;		/* Found it. */
-		MB_PTR_ADV(s);
-	    }
-	if (s == NULL)		/* Not present. */
-	    goto theend;
-    }
-
-    rex.line = line;
-    rex.lnum = 0;
-    reg_toolong = FALSE;
-
-    /* Simplest case: Anchored match need be tried only once. */
-    if (prog->reganch)
-    {
-	int	c;
-
-	if (has_mbyte)
-	    c = (*mb_ptr2char)(rex.line + col);
-	else
-	    c = rex.line[col];
-	if (prog->regstart == NUL
-		|| prog->regstart == c
-		|| (rex.reg_ic
-		    && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c)))
-			|| (c < 255 && prog->regstart < 255 &&
-			    MB_TOLOWER(prog->regstart) == MB_TOLOWER(c)))))
-	    retval = regtry(prog, col, tm, timed_out);
-	else
-	    retval = 0;
-    }
-    else
-    {
-#ifdef FEAT_RELTIME
-	int tm_count = 0;
-#endif
-	/* Messy cases:  unanchored match. */
-	while (!got_int)
-	{
-	    if (prog->regstart != NUL)
-	    {
-		/* Skip until the char we know it must start with.
-		 * Used often, do some work to avoid call overhead. */
-		if (!rex.reg_ic && !has_mbyte)
-		    s = vim_strbyte(rex.line + col, prog->regstart);
-		else
-		    s = cstrchr(rex.line + col, prog->regstart);
-		if (s == NULL)
-		{
-		    retval = 0;
-		    break;
-		}
-		col = (int)(s - rex.line);
-	    }
-
-	    /* Check for maximum column to try. */
-	    if (rex.reg_maxcol > 0 && col >= rex.reg_maxcol)
-	    {
-		retval = 0;
-		break;
-	    }
-
-	    retval = regtry(prog, col, tm, timed_out);
-	    if (retval > 0)
-		break;
-
-	    /* if not currently on the first line, get it again */
-	    if (rex.lnum != 0)
-	    {
-		rex.lnum = 0;
-		rex.line = reg_getline((linenr_T)0);
-	    }
-	    if (rex.line[col] == NUL)
-		break;
-	    if (has_mbyte)
-		col += (*mb_ptr2len)(rex.line + col);
-	    else
-		++col;
-#ifdef FEAT_RELTIME
-	    /* Check for timeout once in a twenty times to avoid overhead. */
-	    if (tm != NULL && ++tm_count == 20)
-	    {
-		tm_count = 0;
-		if (profile_passed_limit(tm))
-		{
-		    if (timed_out != NULL)
-			*timed_out = TRUE;
-		    break;
-		}
-	    }
-#endif
-	}
-    }
-
-theend:
-    /* Free "reg_tofree" when it's a bit big.
-     * Free regstack and backpos if they are bigger than their initial size. */
-    if (reg_tofreelen > 400)
-	VIM_CLEAR(reg_tofree);
-    if (regstack.ga_maxlen > REGSTACK_INITIAL)
-	ga_clear(&regstack);
-    if (backpos.ga_maxlen > BACKPOS_INITIAL)
-	ga_clear(&backpos);
-
-    return retval;
-}
-
 #ifdef FEAT_SYN_HL
 /*
  * Create a new extmatch and mark it as referenced once.
@@ -3974,88 +1214,6 @@ unref_extmatch(reg_extmatch_T *em)
 #endif
 
 /*
- * regtry - try match of "prog" with at rex.line["col"].
- * Returns 0 for failure, number of lines contained in the match otherwise.
- */
-    static long
-regtry(
-    bt_regprog_T	*prog,
-    colnr_T		col,
-    proftime_T		*tm,		/* timeout limit or NULL */
-    int			*timed_out)	/* flag set on timeout or NULL */
-{
-    rex.input = rex.line + col;
-    rex.need_clear_subexpr = TRUE;
-#ifdef FEAT_SYN_HL
-    // Clear the external match subpointers if necessary.
-    rex.need_clear_zsubexpr = (prog->reghasz == REX_SET);
-#endif
-
-    if (regmatch(prog->program + 1, tm, timed_out) == 0)
-	return 0;
-
-    cleanup_subexpr();
-    if (REG_MULTI)
-    {
-	if (rex.reg_startpos[0].lnum < 0)
-	{
-	    rex.reg_startpos[0].lnum = 0;
-	    rex.reg_startpos[0].col = col;
-	}
-	if (rex.reg_endpos[0].lnum < 0)
-	{
-	    rex.reg_endpos[0].lnum = rex.lnum;
-	    rex.reg_endpos[0].col = (int)(rex.input - rex.line);
-	}
-	else
-	    /* Use line number of "\ze". */
-	    rex.lnum = rex.reg_endpos[0].lnum;
-    }
-    else
-    {
-	if (rex.reg_startp[0] == NULL)
-	    rex.reg_startp[0] = rex.line + col;
-	if (rex.reg_endp[0] == NULL)
-	    rex.reg_endp[0] = rex.input;
-    }
-#ifdef FEAT_SYN_HL
-    /* Package any found \z(...\) matches for export. Default is none. */
-    unref_extmatch(re_extmatch_out);
-    re_extmatch_out = NULL;
-
-    if (prog->reghasz == REX_SET)
-    {
-	int		i;
-
-	cleanup_zsubexpr();
-	re_extmatch_out = make_extmatch();
-	for (i = 0; i < NSUBEXP; i++)
-	{
-	    if (REG_MULTI)
-	    {
-		/* Only accept single line matches. */
-		if (reg_startzpos[i].lnum >= 0
-			&& reg_endzpos[i].lnum == reg_startzpos[i].lnum
-			&& reg_endzpos[i].col >= reg_startzpos[i].col)
-		    re_extmatch_out->matches[i] =
-			vim_strnsave(reg_getline(reg_startzpos[i].lnum)
-						       + reg_startzpos[i].col,
-				   reg_endzpos[i].col - reg_startzpos[i].col);
-	    }
-	    else
-	    {
-		if (reg_startzp[i] != NULL && reg_endzp[i] != NULL)
-		    re_extmatch_out->matches[i] =
-			    vim_strnsave(reg_startzp[i],
-					(int)(reg_endzp[i] - reg_startzp[i]));
-	    }
-	}
-    }
-#endif
-    return 1 + rex.lnum;
-}
-
-/*
  * Get class of previous character.
  */
     static int
@@ -4142,1976 +1300,6 @@ reg_match_visual(void)
     return TRUE;
 }
 
-#define ADVANCE_REGINPUT() MB_PTR_ADV(rex.input)
-
-/*
- * The arguments from BRACE_LIMITS are stored here.  They are actually local
- * to regmatch(), but they are here to reduce the amount of stack space used
- * (it can be called recursively many times).
- */
-static long	bl_minval;
-static long	bl_maxval;
-
-/*
- * regmatch - main matching routine
- *
- * Conceptually the strategy is simple: Check to see whether the current node
- * matches, push an item onto the regstack and loop to see whether the rest
- * matches, and then act accordingly.  In practice we make some effort to
- * avoid using the regstack, in particular by going through "ordinary" nodes
- * (that don't need to know whether the rest of the match failed) by a nested
- * loop.
- *
- * Returns TRUE when there is a match.  Leaves rex.input and rex.lnum just after
- * the last matched character.
- * Returns FALSE when there is no match.  Leaves rex.input and rex.lnum in an
- * undefined state!
- */
-    static int
-regmatch(
-    char_u	*scan,		    /* Current node. */
-    proftime_T	*tm UNUSED,	    /* timeout limit or NULL */
-    int		*timed_out UNUSED)  /* flag set on timeout or NULL */
-{
-  char_u	*next;		/* Next node. */
-  int		op;
-  int		c;
-  regitem_T	*rp;
-  int		no;
-  int		status;		/* one of the RA_ values: */
-#define RA_FAIL		1	/* something failed, abort */
-#define RA_CONT		2	/* continue in inner loop */
-#define RA_BREAK	3	/* break inner loop */
-#define RA_MATCH	4	/* successful match */
-#define RA_NOMATCH	5	/* didn't match */
-#ifdef FEAT_RELTIME
-  int		tm_count = 0;
-#endif
-
-  /* Make "regstack" and "backpos" empty.  They are allocated and freed in
-   * bt_regexec_both() to reduce malloc()/free() calls. */
-  regstack.ga_len = 0;
-  backpos.ga_len = 0;
-
-  /*
-   * Repeat until "regstack" is empty.
-   */
-  for (;;)
-  {
-    /* Some patterns may take a long time to match, e.g., "\([a-z]\+\)\+Q".
-     * Allow interrupting them with CTRL-C. */
-    fast_breakcheck();
-
-#ifdef DEBUG
-    if (scan != NULL && regnarrate)
-    {
-	mch_errmsg((char *)regprop(scan));
-	mch_errmsg("(\n");
-    }
-#endif
-
-    /*
-     * Repeat for items that can be matched sequentially, without using the
-     * regstack.
-     */
-    for (;;)
-    {
-	if (got_int || scan == NULL)
-	{
-	    status = RA_FAIL;
-	    break;
-	}
-#ifdef FEAT_RELTIME
-	/* Check for timeout once in a 100 times to avoid overhead. */
-	if (tm != NULL && ++tm_count == 100)
-	{
-	    tm_count = 0;
-	    if (profile_passed_limit(tm))
-	    {
-		if (timed_out != NULL)
-		    *timed_out = TRUE;
-		status = RA_FAIL;
-		break;
-	    }
-	}
-#endif
-	status = RA_CONT;
-
-#ifdef DEBUG
-	if (regnarrate)
-	{
-	    mch_errmsg((char *)regprop(scan));
-	    mch_errmsg("...\n");
-# ifdef FEAT_SYN_HL
-	    if (re_extmatch_in != NULL)
-	    {
-		int i;
-
-		mch_errmsg(_("External submatches:\n"));
-		for (i = 0; i < NSUBEXP; i++)
-		{
-		    mch_errmsg("    \"");
-		    if (re_extmatch_in->matches[i] != NULL)
-			mch_errmsg((char *)re_extmatch_in->matches[i]);
-		    mch_errmsg("\"\n");
-		}
-	    }
-# endif
-	}
-#endif
-	next = regnext(scan);
-
-	op = OP(scan);
-	/* Check for character class with NL added. */
-	if (!rex.reg_line_lbr && WITH_NL(op) && REG_MULTI
-			     && *rex.input == NUL && rex.lnum <= rex.reg_maxline)
-	{
-	    reg_nextline();
-	}
-	else if (rex.reg_line_lbr && WITH_NL(op) && *rex.input == '\n')
-	{
-	    ADVANCE_REGINPUT();
-	}
-	else
-	{
-	  if (WITH_NL(op))
-	      op -= ADD_NL;
-	  if (has_mbyte)
-	      c = (*mb_ptr2char)(rex.input);
-	  else
-	      c = *rex.input;
-	  switch (op)
-	  {
-	  case BOL:
-	    if (rex.input != rex.line)
-		status = RA_NOMATCH;
-	    break;
-
-	  case EOL:
-	    if (c != NUL)
-		status = RA_NOMATCH;
-	    break;
-
-	  case RE_BOF:
-	    /* We're not at the beginning of the file when below the first
-	     * line where we started, not at the start of the line or we
-	     * didn't start at the first line of the buffer. */
-	    if (rex.lnum != 0 || rex.input != rex.line
-				       || (REG_MULTI && rex.reg_firstlnum > 1))
-		status = RA_NOMATCH;
-	    break;
-
-	  case RE_EOF:
-	    if (rex.lnum != rex.reg_maxline || c != NUL)
-		status = RA_NOMATCH;
-	    break;
-
-	  case CURSOR:
-	    /* Check if the buffer is in a window and compare the
-	     * rex.reg_win->w_cursor position to the match position. */
-	    if (rex.reg_win == NULL
-		    || (rex.lnum + rex.reg_firstlnum
-						 != rex.reg_win->w_cursor.lnum)
-		    || ((colnr_T)(rex.input - rex.line)
-						 != rex.reg_win->w_cursor.col))
-		status = RA_NOMATCH;
-	    break;
-
-	  case RE_MARK:
-	    /* Compare the mark position to the match position. */
-	    {
-		int	mark = OPERAND(scan)[0];
-		int	cmp = OPERAND(scan)[1];
-		pos_T	*pos;
-
-		pos = getmark_buf(rex.reg_buf, mark, FALSE);
-		if (pos == NULL		     /* mark doesn't exist */
-			|| pos->lnum <= 0    /* mark isn't set in reg_buf */
-			|| (pos->lnum == rex.lnum + rex.reg_firstlnum
-				? (pos->col == (colnr_T)(rex.input - rex.line)
-				    ? (cmp == '<' || cmp == '>')
-				    : (pos->col < (colnr_T)(rex.input - rex.line)
-					? cmp != '>'
-					: cmp != '<'))
-				: (pos->lnum < rex.lnum + rex.reg_firstlnum
-				    ? cmp != '>'
-				    : cmp != '<')))
-		    status = RA_NOMATCH;
-	    }
-	    break;
-
-	  case RE_VISUAL:
-	    if (!reg_match_visual())
-		status = RA_NOMATCH;
-	    break;
-
-	  case RE_LNUM:
-	    if (!REG_MULTI || !re_num_cmp((long_u)(rex.lnum + rex.reg_firstlnum),
-									scan))
-		status = RA_NOMATCH;
-	    break;
-
-	  case RE_COL:
-	    if (!re_num_cmp((long_u)(rex.input - rex.line) + 1, scan))
-		status = RA_NOMATCH;
-	    break;
-
-	  case RE_VCOL:
-	    if (!re_num_cmp((long_u)win_linetabsize(
-			    rex.reg_win == NULL ? curwin : rex.reg_win,
-			    rex.line, (colnr_T)(rex.input - rex.line)) + 1, scan))
-		status = RA_NOMATCH;
-	    break;
-
-	  case BOW:	/* \<word; rex.input points to w */
-	    if (c == NUL)	/* Can't match at end of line */
-		status = RA_NOMATCH;
-	    else if (has_mbyte)
-	    {
-		int this_class;
-
-		/* Get class of current and previous char (if it exists). */
-		this_class = mb_get_class_buf(rex.input, rex.reg_buf);
-		if (this_class <= 1)
-		    status = RA_NOMATCH;  /* not on a word at all */
-		else if (reg_prev_class() == this_class)
-		    status = RA_NOMATCH;  /* previous char is in same word */
-	    }
-	    else
-	    {
-		if (!vim_iswordc_buf(c, rex.reg_buf) || (rex.input > rex.line
-				&& vim_iswordc_buf(rex.input[-1], rex.reg_buf)))
-		    status = RA_NOMATCH;
-	    }
-	    break;
-
-	  case EOW:	/* word\>; rex.input points after d */
-	    if (rex.input == rex.line)    /* Can't match at start of line */
-		status = RA_NOMATCH;
-	    else if (has_mbyte)
-	    {
-		int this_class, prev_class;
-
-		/* Get class of current and previous char (if it exists). */
-		this_class = mb_get_class_buf(rex.input, rex.reg_buf);
-		prev_class = reg_prev_class();
-		if (this_class == prev_class
-			|| prev_class == 0 || prev_class == 1)
-		    status = RA_NOMATCH;
-	    }
-	    else
-	    {
-		if (!vim_iswordc_buf(rex.input[-1], rex.reg_buf)
-			|| (rex.input[0] != NUL
-					   && vim_iswordc_buf(c, rex.reg_buf)))
-		    status = RA_NOMATCH;
-	    }
-	    break; /* Matched with EOW */
-
-	  case ANY:
-	    /* ANY does not match new lines. */
-	    if (c == NUL)
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case IDENT:
-	    if (!vim_isIDc(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case SIDENT:
-	    if (VIM_ISDIGIT(*rex.input) || !vim_isIDc(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case KWORD:
-	    if (!vim_iswordp_buf(rex.input, rex.reg_buf))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case SKWORD:
-	    if (VIM_ISDIGIT(*rex.input)
-				    || !vim_iswordp_buf(rex.input, rex.reg_buf))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case FNAME:
-	    if (!vim_isfilec(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case SFNAME:
-	    if (VIM_ISDIGIT(*rex.input) || !vim_isfilec(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case PRINT:
-	    if (!vim_isprintc(PTR2CHAR(rex.input)))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case SPRINT:
-	    if (VIM_ISDIGIT(*rex.input) || !vim_isprintc(PTR2CHAR(rex.input)))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case WHITE:
-	    if (!VIM_ISWHITE(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case NWHITE:
-	    if (c == NUL || VIM_ISWHITE(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case DIGIT:
-	    if (!ri_digit(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case NDIGIT:
-	    if (c == NUL || ri_digit(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case HEX:
-	    if (!ri_hex(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case NHEX:
-	    if (c == NUL || ri_hex(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case OCTAL:
-	    if (!ri_octal(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case NOCTAL:
-	    if (c == NUL || ri_octal(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case WORD:
-	    if (!ri_word(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case NWORD:
-	    if (c == NUL || ri_word(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case HEAD:
-	    if (!ri_head(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case NHEAD:
-	    if (c == NUL || ri_head(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case ALPHA:
-	    if (!ri_alpha(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case NALPHA:
-	    if (c == NUL || ri_alpha(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case LOWER:
-	    if (!ri_lower(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case NLOWER:
-	    if (c == NUL || ri_lower(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case UPPER:
-	    if (!ri_upper(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case NUPPER:
-	    if (c == NUL || ri_upper(c))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case EXACTLY:
-	    {
-		int	len;
-		char_u	*opnd;
-
-		opnd = OPERAND(scan);
-		/* Inline the first byte, for speed. */
-		if (*opnd != *rex.input
-			&& (!rex.reg_ic
-			    || (!enc_utf8
-			      && MB_TOLOWER(*opnd) != MB_TOLOWER(*rex.input))))
-		    status = RA_NOMATCH;
-		else if (*opnd == NUL)
-		{
-		    /* match empty string always works; happens when "~" is
-		     * empty. */
-		}
-		else
-		{
-		    if (opnd[1] == NUL && !(enc_utf8 && rex.reg_ic))
-		    {
-			len = 1;	/* matched a single byte above */
-		    }
-		    else
-		    {
-			/* Need to match first byte again for multi-byte. */
-			len = (int)STRLEN(opnd);
-			if (cstrncmp(opnd, rex.input, &len) != 0)
-			    status = RA_NOMATCH;
-		    }
-		    /* Check for following composing character, unless %C
-		     * follows (skips over all composing chars). */
-		    if (status != RA_NOMATCH
-			    && enc_utf8
-			    && UTF_COMPOSINGLIKE(rex.input, rex.input + len)
-			    && !rex.reg_icombine
-			    && OP(next) != RE_COMPOSING)
-		    {
-			/* raaron: This code makes a composing character get
-			 * ignored, which is the correct behavior (sometimes)
-			 * for voweled Hebrew texts. */
-			status = RA_NOMATCH;
-		    }
-		    if (status != RA_NOMATCH)
-			rex.input += len;
-		}
-	    }
-	    break;
-
-	  case ANYOF:
-	  case ANYBUT:
-	    if (c == NUL)
-		status = RA_NOMATCH;
-	    else if ((cstrchr(OPERAND(scan), c) == NULL) == (op == ANYOF))
-		status = RA_NOMATCH;
-	    else
-		ADVANCE_REGINPUT();
-	    break;
-
-	  case MULTIBYTECODE:
-	    if (has_mbyte)
-	    {
-		int	i, len;
-		char_u	*opnd;
-		int	opndc = 0, inpc;
-
-		opnd = OPERAND(scan);
-		/* Safety check (just in case 'encoding' was changed since
-		 * compiling the program). */
-		if ((len = (*mb_ptr2len)(opnd)) < 2)
-		{
-		    status = RA_NOMATCH;
-		    break;
-		}
-		if (enc_utf8)
-		    opndc = utf_ptr2char(opnd);
-		if (enc_utf8 && utf_iscomposing(opndc))
-		{
-		    /* When only a composing char is given match at any
-		     * position where that composing char appears. */
-		    status = RA_NOMATCH;
-		    for (i = 0; rex.input[i] != NUL;
-						i += utf_ptr2len(rex.input + i))
-		    {
-			inpc = utf_ptr2char(rex.input + i);
-			if (!utf_iscomposing(inpc))
-			{
-			    if (i > 0)
-				break;
-			}
-			else if (opndc == inpc)
-			{
-			    /* Include all following composing chars. */
-			    len = i + utfc_ptr2len(rex.input + i);
-			    status = RA_MATCH;
-			    break;
-			}
-		    }
-		}
-		else
-		    for (i = 0; i < len; ++i)
-			if (opnd[i] != rex.input[i])
-			{
-			    status = RA_NOMATCH;
-			    break;
-			}
-		rex.input += len;
-	    }
-	    else
-		status = RA_NOMATCH;
-	    break;
-	  case RE_COMPOSING:
-	    if (enc_utf8)
-	    {
-		/* Skip composing characters. */
-		while (utf_iscomposing(utf_ptr2char(rex.input)))
-		    MB_CPTR_ADV(rex.input);
-	    }
-	    break;
-
-	  case NOTHING:
-	    break;
-
-	  case BACK:
-	    {
-		int		i;
-		backpos_T	*bp;
-
-		/*
-		 * When we run into BACK we need to check if we don't keep
-		 * looping without matching any input.  The second and later
-		 * times a BACK is encountered it fails if the input is still
-		 * at the same position as the previous time.
-		 * The positions are stored in "backpos" and found by the
-		 * current value of "scan", the position in the RE program.
-		 */
-		bp = (backpos_T *)backpos.ga_data;
-		for (i = 0; i < backpos.ga_len; ++i)
-		    if (bp[i].bp_scan == scan)
-			break;
-		if (i == backpos.ga_len)
-		{
-		    /* First time at this BACK, make room to store the pos. */
-		    if (ga_grow(&backpos, 1) == FAIL)
-			status = RA_FAIL;
-		    else
-		    {
-			/* get "ga_data" again, it may have changed */
-			bp = (backpos_T *)backpos.ga_data;
-			bp[i].bp_scan = scan;
-			++backpos.ga_len;
-		    }
-		}
-		else if (reg_save_equal(&bp[i].bp_pos))
-		    /* Still at same position as last time, fail. */
-		    status = RA_NOMATCH;
-
-		if (status != RA_FAIL && status != RA_NOMATCH)
-		    reg_save(&bp[i].bp_pos, &backpos);
-	    }
-	    break;
-
-	  case MOPEN + 0:   /* Match start: \zs */
-	  case MOPEN + 1:   /* \( */
-	  case MOPEN + 2:
-	  case MOPEN + 3:
-	  case MOPEN + 4:
-	  case MOPEN + 5:
-	  case MOPEN + 6:
-	  case MOPEN + 7:
-	  case MOPEN + 8:
-	  case MOPEN + 9:
-	    {
-		no = op - MOPEN;
-		cleanup_subexpr();
-		rp = regstack_push(RS_MOPEN, scan);
-		if (rp == NULL)
-		    status = RA_FAIL;
-		else
-		{
-		    rp->rs_no = no;
-		    save_se(&rp->rs_un.sesave, &rex.reg_startpos[no],
-							  &rex.reg_startp[no]);
-		    /* We simply continue and handle the result when done. */
-		}
-	    }
-	    break;
-
-	  case NOPEN:	    /* \%( */
-	  case NCLOSE:	    /* \) after \%( */
-		if (regstack_push(RS_NOPEN, scan) == NULL)
-		    status = RA_FAIL;
-		/* We simply continue and handle the result when done. */
-		break;
-
-#ifdef FEAT_SYN_HL
-	  case ZOPEN + 1:
-	  case ZOPEN + 2:
-	  case ZOPEN + 3:
-	  case ZOPEN + 4:
-	  case ZOPEN + 5:
-	  case ZOPEN + 6:
-	  case ZOPEN + 7:
-	  case ZOPEN + 8:
-	  case ZOPEN + 9:
-	    {
-		no = op - ZOPEN;
-		cleanup_zsubexpr();
-		rp = regstack_push(RS_ZOPEN, scan);
-		if (rp == NULL)
-		    status = RA_FAIL;
-		else
-		{
-		    rp->rs_no = no;
-		    save_se(&rp->rs_un.sesave, &reg_startzpos[no],
-							     &reg_startzp[no]);
-		    /* We simply continue and handle the result when done. */
-		}
-	    }
-	    break;
-#endif
-
-	  case MCLOSE + 0:  /* Match end: \ze */
-	  case MCLOSE + 1:  /* \) */
-	  case MCLOSE + 2:
-	  case MCLOSE + 3:
-	  case MCLOSE + 4:
-	  case MCLOSE + 5:
-	  case MCLOSE + 6:
-	  case MCLOSE + 7:
-	  case MCLOSE + 8:
-	  case MCLOSE + 9:
-	    {
-		no = op - MCLOSE;
-		cleanup_subexpr();
-		rp = regstack_push(RS_MCLOSE, scan);
-		if (rp == NULL)
-		    status = RA_FAIL;
-		else
-		{
-		    rp->rs_no = no;
-		    save_se(&rp->rs_un.sesave, &rex.reg_endpos[no],
-							    &rex.reg_endp[no]);
-		    /* We simply continue and handle the result when done. */
-		}
-	    }
-	    break;
-
-#ifdef FEAT_SYN_HL
-	  case ZCLOSE + 1:  /* \) after \z( */
-	  case ZCLOSE + 2:
-	  case ZCLOSE + 3:
-	  case ZCLOSE + 4:
-	  case ZCLOSE + 5:
-	  case ZCLOSE + 6:
-	  case ZCLOSE + 7:
-	  case ZCLOSE + 8:
-	  case ZCLOSE + 9:
-	    {
-		no = op - ZCLOSE;
-		cleanup_zsubexpr();
-		rp = regstack_push(RS_ZCLOSE, scan);
-		if (rp == NULL)
-		    status = RA_FAIL;
-		else
-		{
-		    rp->rs_no = no;
-		    save_se(&rp->rs_un.sesave, &reg_endzpos[no],
-							      &reg_endzp[no]);
-		    /* We simply continue and handle the result when done. */
-		}
-	    }
-	    break;
-#endif
-
-	  case BACKREF + 1:
-	  case BACKREF + 2:
-	  case BACKREF + 3:
-	  case BACKREF + 4:
-	  case BACKREF + 5:
-	  case BACKREF + 6:
-	  case BACKREF + 7:
-	  case BACKREF + 8:
-	  case BACKREF + 9:
-	    {
-		int		len;
-
-		no = op - BACKREF;
-		cleanup_subexpr();
-		if (!REG_MULTI)		/* Single-line regexp */
-		{
-		    if (rex.reg_startp[no] == NULL || rex.reg_endp[no] == NULL)
-		    {
-			/* Backref was not set: Match an empty string. */
-			len = 0;
-		    }
-		    else
-		    {
-			/* Compare current input with back-ref in the same
-			 * line. */
-			len = (int)(rex.reg_endp[no] - rex.reg_startp[no]);
-			if (cstrncmp(rex.reg_startp[no], rex.input, &len) != 0)
-			    status = RA_NOMATCH;
-		    }
-		}
-		else				/* Multi-line regexp */
-		{
-		    if (rex.reg_startpos[no].lnum < 0
-						|| rex.reg_endpos[no].lnum < 0)
-		    {
-			/* Backref was not set: Match an empty string. */
-			len = 0;
-		    }
-		    else
-		    {
-			if (rex.reg_startpos[no].lnum == rex.lnum
-				&& rex.reg_endpos[no].lnum == rex.lnum)
-			{
-			    /* Compare back-ref within the current line. */
-			    len = rex.reg_endpos[no].col
-						    - rex.reg_startpos[no].col;
-			    if (cstrncmp(rex.line + rex.reg_startpos[no].col,
-							  rex.input, &len) != 0)
-				status = RA_NOMATCH;
-			}
-			else
-			{
-			    /* Messy situation: Need to compare between two
-			     * lines. */
-			    int r = match_with_backref(
-					    rex.reg_startpos[no].lnum,
-					    rex.reg_startpos[no].col,
-					    rex.reg_endpos[no].lnum,
-					    rex.reg_endpos[no].col,
-					    &len);
-
-			    if (r != RA_MATCH)
-				status = r;
-			}
-		    }
-		}
-
-		/* Matched the backref, skip over it. */
-		rex.input += len;
-	    }
-	    break;
-
-#ifdef FEAT_SYN_HL
-	  case ZREF + 1:
-	  case ZREF + 2:
-	  case ZREF + 3:
-	  case ZREF + 4:
-	  case ZREF + 5:
-	  case ZREF + 6:
-	  case ZREF + 7:
-	  case ZREF + 8:
-	  case ZREF + 9:
-	    {
-		int	len;
-
-		cleanup_zsubexpr();
-		no = op - ZREF;
-		if (re_extmatch_in != NULL
-			&& re_extmatch_in->matches[no] != NULL)
-		{
-		    len = (int)STRLEN(re_extmatch_in->matches[no]);
-		    if (cstrncmp(re_extmatch_in->matches[no],
-							  rex.input, &len) != 0)
-			status = RA_NOMATCH;
-		    else
-			rex.input += len;
-		}
-		else
-		{
-		    /* Backref was not set: Match an empty string. */
-		}
-	    }
-	    break;
-#endif
-
-	  case BRANCH:
-	    {
-		if (OP(next) != BRANCH) /* No choice. */
-		    next = OPERAND(scan);	/* Avoid recursion. */
-		else
-		{
-		    rp = regstack_push(RS_BRANCH, scan);
-		    if (rp == NULL)
-			status = RA_FAIL;
-		    else
-			status = RA_BREAK;	/* rest is below */
-		}
-	    }
-	    break;
-
-	  case BRACE_LIMITS:
-	    {
-		if (OP(next) == BRACE_SIMPLE)
-		{
-		    bl_minval = OPERAND_MIN(scan);
-		    bl_maxval = OPERAND_MAX(scan);
-		}
-		else if (OP(next) >= BRACE_COMPLEX
-			&& OP(next) < BRACE_COMPLEX + 10)
-		{
-		    no = OP(next) - BRACE_COMPLEX;
-		    brace_min[no] = OPERAND_MIN(scan);
-		    brace_max[no] = OPERAND_MAX(scan);
-		    brace_count[no] = 0;
-		}
-		else
-		{
-		    internal_error("BRACE_LIMITS");
-		    status = RA_FAIL;
-		}
-	    }
-	    break;
-
-	  case BRACE_COMPLEX + 0:
-	  case BRACE_COMPLEX + 1:
-	  case BRACE_COMPLEX + 2:
-	  case BRACE_COMPLEX + 3:
-	  case BRACE_COMPLEX + 4:
-	  case BRACE_COMPLEX + 5:
-	  case BRACE_COMPLEX + 6:
-	  case BRACE_COMPLEX + 7:
-	  case BRACE_COMPLEX + 8:
-	  case BRACE_COMPLEX + 9:
-	    {
-		no = op - BRACE_COMPLEX;
-		++brace_count[no];
-
-		/* If not matched enough times yet, try one more */
-		if (brace_count[no] <= (brace_min[no] <= brace_max[no]
-					     ? brace_min[no] : brace_max[no]))
-		{
-		    rp = regstack_push(RS_BRCPLX_MORE, scan);
-		    if (rp == NULL)
-			status = RA_FAIL;
-		    else
-		    {
-			rp->rs_no = no;
-			reg_save(&rp->rs_un.regsave, &backpos);
-			next = OPERAND(scan);
-			/* We continue and handle the result when done. */
-		    }
-		    break;
-		}
-
-		/* If matched enough times, may try matching some more */
-		if (brace_min[no] <= brace_max[no])
-		{
-		    /* Range is the normal way around, use longest match */
-		    if (brace_count[no] <= brace_max[no])
-		    {
-			rp = regstack_push(RS_BRCPLX_LONG, scan);
-			if (rp == NULL)
-			    status = RA_FAIL;
-			else
-			{
-			    rp->rs_no = no;
-			    reg_save(&rp->rs_un.regsave, &backpos);
-			    next = OPERAND(scan);
-			    /* We continue and handle the result when done. */
-			}
-		    }
-		}
-		else
-		{
-		    /* Range is backwards, use shortest match first */
-		    if (brace_count[no] <= brace_min[no])
-		    {
-			rp = regstack_push(RS_BRCPLX_SHORT, scan);
-			if (rp == NULL)
-			    status = RA_FAIL;
-			else
-			{
-			    reg_save(&rp->rs_un.regsave, &backpos);
-			    /* We continue and handle the result when done. */
-			}
-		    }
-		}
-	    }
-	    break;
-
-	  case BRACE_SIMPLE:
-	  case STAR:
-	  case PLUS:
-	    {
-		regstar_T	rst;
-
-		/*
-		 * Lookahead to avoid useless match attempts when we know
-		 * what character comes next.
-		 */
-		if (OP(next) == EXACTLY)
-		{
-		    rst.nextb = *OPERAND(next);
-		    if (rex.reg_ic)
-		    {
-			if (MB_ISUPPER(rst.nextb))
-			    rst.nextb_ic = MB_TOLOWER(rst.nextb);
-			else
-			    rst.nextb_ic = MB_TOUPPER(rst.nextb);
-		    }
-		    else
-			rst.nextb_ic = rst.nextb;
-		}
-		else
-		{
-		    rst.nextb = NUL;
-		    rst.nextb_ic = NUL;
-		}
-		if (op != BRACE_SIMPLE)
-		{
-		    rst.minval = (op == STAR) ? 0 : 1;
-		    rst.maxval = MAX_LIMIT;
-		}
-		else
-		{
-		    rst.minval = bl_minval;
-		    rst.maxval = bl_maxval;
-		}
-
-		/*
-		 * When maxval > minval, try matching as much as possible, up
-		 * to maxval.  When maxval < minval, try matching at least the
-		 * minimal number (since the range is backwards, that's also
-		 * maxval!).
-		 */
-		rst.count = regrepeat(OPERAND(scan), rst.maxval);
-		if (got_int)
-		{
-		    status = RA_FAIL;
-		    break;
-		}
-		if (rst.minval <= rst.maxval
-			  ? rst.count >= rst.minval : rst.count >= rst.maxval)
-		{
-		    /* It could match.  Prepare for trying to match what
-		     * follows.  The code is below.  Parameters are stored in
-		     * a regstar_T on the regstack. */
-		    if ((long)((unsigned)regstack.ga_len >> 10) >= p_mmp)
-		    {
-			emsg(_(e_maxmempat));
-			status = RA_FAIL;
-		    }
-		    else if (ga_grow(&regstack, sizeof(regstar_T)) == FAIL)
-			status = RA_FAIL;
-		    else
-		    {
-			regstack.ga_len += sizeof(regstar_T);
-			rp = regstack_push(rst.minval <= rst.maxval
-					? RS_STAR_LONG : RS_STAR_SHORT, scan);
-			if (rp == NULL)
-			    status = RA_FAIL;
-			else
-			{
-			    *(((regstar_T *)rp) - 1) = rst;
-			    status = RA_BREAK;	    /* skip the restore bits */
-			}
-		    }
-		}
-		else
-		    status = RA_NOMATCH;
-
-	    }
-	    break;
-
-	  case NOMATCH:
-	  case MATCH:
-	  case SUBPAT:
-	    rp = regstack_push(RS_NOMATCH, scan);
-	    if (rp == NULL)
-		status = RA_FAIL;
-	    else
-	    {
-		rp->rs_no = op;
-		reg_save(&rp->rs_un.regsave, &backpos);
-		next = OPERAND(scan);
-		/* We continue and handle the result when done. */
-	    }
-	    break;
-
-	  case BEHIND:
-	  case NOBEHIND:
-	    /* Need a bit of room to store extra positions. */
-	    if ((long)((unsigned)regstack.ga_len >> 10) >= p_mmp)
-	    {
-		emsg(_(e_maxmempat));
-		status = RA_FAIL;
-	    }
-	    else if (ga_grow(&regstack, sizeof(regbehind_T)) == FAIL)
-		status = RA_FAIL;
-	    else
-	    {
-		regstack.ga_len += sizeof(regbehind_T);
-		rp = regstack_push(RS_BEHIND1, scan);
-		if (rp == NULL)
-		    status = RA_FAIL;
-		else
-		{
-		    /* Need to save the subexpr to be able to restore them
-		     * when there is a match but we don't use it. */
-		    save_subexpr(((regbehind_T *)rp) - 1);
-
-		    rp->rs_no = op;
-		    reg_save(&rp->rs_un.regsave, &backpos);
-		    /* First try if what follows matches.  If it does then we
-		     * check the behind match by looping. */
-		}
-	    }
-	    break;
-
-	  case BHPOS:
-	    if (REG_MULTI)
-	    {
-		if (behind_pos.rs_u.pos.col != (colnr_T)(rex.input - rex.line)
-			|| behind_pos.rs_u.pos.lnum != rex.lnum)
-		    status = RA_NOMATCH;
-	    }
-	    else if (behind_pos.rs_u.ptr != rex.input)
-		status = RA_NOMATCH;
-	    break;
-
-	  case NEWL:
-	    if ((c != NUL || !REG_MULTI || rex.lnum > rex.reg_maxline
-			     || rex.reg_line_lbr)
-					   && (c != '\n' || !rex.reg_line_lbr))
-		status = RA_NOMATCH;
-	    else if (rex.reg_line_lbr)
-		ADVANCE_REGINPUT();
-	    else
-		reg_nextline();
-	    break;
-
-	  case END:
-	    status = RA_MATCH;	/* Success! */
-	    break;
-
-	  default:
-	    emsg(_(e_re_corr));
-#ifdef DEBUG
-	    printf("Illegal op code %d\n", op);
-#endif
-	    status = RA_FAIL;
-	    break;
-	  }
-	}
-
-	/* If we can't continue sequentially, break the inner loop. */
-	if (status != RA_CONT)
-	    break;
-
-	/* Continue in inner loop, advance to next item. */
-	scan = next;
-
-    } /* end of inner loop */
-
-    /*
-     * If there is something on the regstack execute the code for the state.
-     * If the state is popped then loop and use the older state.
-     */
-    while (regstack.ga_len > 0 && status != RA_FAIL)
-    {
-	rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len) - 1;
-	switch (rp->rs_state)
-	{
-	  case RS_NOPEN:
-	    /* Result is passed on as-is, simply pop the state. */
-	    regstack_pop(&scan);
-	    break;
-
-	  case RS_MOPEN:
-	    /* Pop the state.  Restore pointers when there is no match. */
-	    if (status == RA_NOMATCH)
-		restore_se(&rp->rs_un.sesave, &rex.reg_startpos[rp->rs_no],
-						  &rex.reg_startp[rp->rs_no]);
-	    regstack_pop(&scan);
-	    break;
-
-#ifdef FEAT_SYN_HL
-	  case RS_ZOPEN:
-	    /* Pop the state.  Restore pointers when there is no match. */
-	    if (status == RA_NOMATCH)
-		restore_se(&rp->rs_un.sesave, &reg_startzpos[rp->rs_no],
-						 &reg_startzp[rp->rs_no]);
-	    regstack_pop(&scan);
-	    break;
-#endif
-
-	  case RS_MCLOSE:
-	    /* Pop the state.  Restore pointers when there is no match. */
-	    if (status == RA_NOMATCH)
-		restore_se(&rp->rs_un.sesave, &rex.reg_endpos[rp->rs_no],
-						    &rex.reg_endp[rp->rs_no]);
-	    regstack_pop(&scan);
-	    break;
-
-#ifdef FEAT_SYN_HL
-	  case RS_ZCLOSE:
-	    /* Pop the state.  Restore pointers when there is no match. */
-	    if (status == RA_NOMATCH)
-		restore_se(&rp->rs_un.sesave, &reg_endzpos[rp->rs_no],
-						   &reg_endzp[rp->rs_no]);
-	    regstack_pop(&scan);
-	    break;
-#endif
-
-	  case RS_BRANCH:
-	    if (status == RA_MATCH)
-		/* this branch matched, use it */
-		regstack_pop(&scan);
-	    else
-	    {
-		if (status != RA_BREAK)
-		{
-		    /* After a non-matching branch: try next one. */
-		    reg_restore(&rp->rs_un.regsave, &backpos);
-		    scan = rp->rs_scan;
-		}
-		if (scan == NULL || OP(scan) != BRANCH)
-		{
-		    /* no more branches, didn't find a match */
-		    status = RA_NOMATCH;
-		    regstack_pop(&scan);
-		}
-		else
-		{
-		    /* Prepare to try a branch. */
-		    rp->rs_scan = regnext(scan);
-		    reg_save(&rp->rs_un.regsave, &backpos);
-		    scan = OPERAND(scan);
-		}
-	    }
-	    break;
-
-	  case RS_BRCPLX_MORE:
-	    /* Pop the state.  Restore pointers when there is no match. */
-	    if (status == RA_NOMATCH)
-	    {
-		reg_restore(&rp->rs_un.regsave, &backpos);
-		--brace_count[rp->rs_no];	/* decrement match count */
-	    }
-	    regstack_pop(&scan);
-	    break;
-
-	  case RS_BRCPLX_LONG:
-	    /* Pop the state.  Restore pointers when there is no match. */
-	    if (status == RA_NOMATCH)
-	    {
-		/* There was no match, but we did find enough matches. */
-		reg_restore(&rp->rs_un.regsave, &backpos);
-		--brace_count[rp->rs_no];
-		/* continue with the items after "\{}" */
-		status = RA_CONT;
-	    }
-	    regstack_pop(&scan);
-	    if (status == RA_CONT)
-		scan = regnext(scan);
-	    break;
-
-	  case RS_BRCPLX_SHORT:
-	    /* Pop the state.  Restore pointers when there is no match. */
-	    if (status == RA_NOMATCH)
-		/* There was no match, try to match one more item. */
-		reg_restore(&rp->rs_un.regsave, &backpos);
-	    regstack_pop(&scan);
-	    if (status == RA_NOMATCH)
-	    {
-		scan = OPERAND(scan);
-		status = RA_CONT;
-	    }
-	    break;
-
-	  case RS_NOMATCH:
-	    /* Pop the state.  If the operand matches for NOMATCH or
-	     * doesn't match for MATCH/SUBPAT, we fail.  Otherwise backup,
-	     * except for SUBPAT, and continue with the next item. */
-	    if (status == (rp->rs_no == NOMATCH ? RA_MATCH : RA_NOMATCH))
-		status = RA_NOMATCH;
-	    else
-	    {
-		status = RA_CONT;
-		if (rp->rs_no != SUBPAT)	/* zero-width */
-		    reg_restore(&rp->rs_un.regsave, &backpos);
-	    }
-	    regstack_pop(&scan);
-	    if (status == RA_CONT)
-		scan = regnext(scan);
-	    break;
-
-	  case RS_BEHIND1:
-	    if (status == RA_NOMATCH)
-	    {
-		regstack_pop(&scan);
-		regstack.ga_len -= sizeof(regbehind_T);
-	    }
-	    else
-	    {
-		/* The stuff after BEHIND/NOBEHIND matches.  Now try if
-		 * the behind part does (not) match before the current
-		 * position in the input.  This must be done at every
-		 * position in the input and checking if the match ends at
-		 * the current position. */
-
-		/* save the position after the found match for next */
-		reg_save(&(((regbehind_T *)rp) - 1)->save_after, &backpos);
-
-		/* Start looking for a match with operand at the current
-		 * position.  Go back one character until we find the
-		 * result, hitting the start of the line or the previous
-		 * line (for multi-line matching).
-		 * Set behind_pos to where the match should end, BHPOS
-		 * will match it.  Save the current value. */
-		(((regbehind_T *)rp) - 1)->save_behind = behind_pos;
-		behind_pos = rp->rs_un.regsave;
-
-		rp->rs_state = RS_BEHIND2;
-
-		reg_restore(&rp->rs_un.regsave, &backpos);
-		scan = OPERAND(rp->rs_scan) + 4;
-	    }
-	    break;
-
-	  case RS_BEHIND2:
-	    /*
-	     * Looping for BEHIND / NOBEHIND match.
-	     */
-	    if (status == RA_MATCH && reg_save_equal(&behind_pos))
-	    {
-		/* found a match that ends where "next" started */
-		behind_pos = (((regbehind_T *)rp) - 1)->save_behind;
-		if (rp->rs_no == BEHIND)
-		    reg_restore(&(((regbehind_T *)rp) - 1)->save_after,
-								    &backpos);
-		else
-		{
-		    /* But we didn't want a match.  Need to restore the
-		     * subexpr, because what follows matched, so they have
-		     * been set. */
-		    status = RA_NOMATCH;
-		    restore_subexpr(((regbehind_T *)rp) - 1);
-		}
-		regstack_pop(&scan);
-		regstack.ga_len -= sizeof(regbehind_T);
-	    }
-	    else
-	    {
-		long limit;
-
-		/* No match or a match that doesn't end where we want it: Go
-		 * back one character.  May go to previous line once. */
-		no = OK;
-		limit = OPERAND_MIN(rp->rs_scan);
-		if (REG_MULTI)
-		{
-		    if (limit > 0
-			    && ((rp->rs_un.regsave.rs_u.pos.lnum
-						    < behind_pos.rs_u.pos.lnum
-				    ? (colnr_T)STRLEN(rex.line)
-				    : behind_pos.rs_u.pos.col)
-				- rp->rs_un.regsave.rs_u.pos.col >= limit))
-			no = FAIL;
-		    else if (rp->rs_un.regsave.rs_u.pos.col == 0)
-		    {
-			if (rp->rs_un.regsave.rs_u.pos.lnum
-					< behind_pos.rs_u.pos.lnum
-				|| reg_getline(
-					--rp->rs_un.regsave.rs_u.pos.lnum)
-								  == NULL)
-			    no = FAIL;
-			else
-			{
-			    reg_restore(&rp->rs_un.regsave, &backpos);
-			    rp->rs_un.regsave.rs_u.pos.col =
-						 (colnr_T)STRLEN(rex.line);
-			}
-		    }
-		    else
-		    {
-			if (has_mbyte)
-			{
-			    char_u *line =
-				  reg_getline(rp->rs_un.regsave.rs_u.pos.lnum);
-
-			    rp->rs_un.regsave.rs_u.pos.col -=
-				(*mb_head_off)(line, line
-				    + rp->rs_un.regsave.rs_u.pos.col - 1) + 1;
-			}
-			else
-			    --rp->rs_un.regsave.rs_u.pos.col;
-		    }
-		}
-		else
-		{
-		    if (rp->rs_un.regsave.rs_u.ptr == rex.line)
-			no = FAIL;
-		    else
-		    {
-			MB_PTR_BACK(rex.line, rp->rs_un.regsave.rs_u.ptr);
-			if (limit > 0 && (long)(behind_pos.rs_u.ptr
-				     - rp->rs_un.regsave.rs_u.ptr) > limit)
-			    no = FAIL;
-		    }
-		}
-		if (no == OK)
-		{
-		    /* Advanced, prepare for finding match again. */
-		    reg_restore(&rp->rs_un.regsave, &backpos);
-		    scan = OPERAND(rp->rs_scan) + 4;
-		    if (status == RA_MATCH)
-		    {
-			/* We did match, so subexpr may have been changed,
-			 * need to restore them for the next try. */
-			status = RA_NOMATCH;
-			restore_subexpr(((regbehind_T *)rp) - 1);
-		    }
-		}
-		else
-		{
-		    /* Can't advance.  For NOBEHIND that's a match. */
-		    behind_pos = (((regbehind_T *)rp) - 1)->save_behind;
-		    if (rp->rs_no == NOBEHIND)
-		    {
-			reg_restore(&(((regbehind_T *)rp) - 1)->save_after,
-								    &backpos);
-			status = RA_MATCH;
-		    }
-		    else
-		    {
-			/* We do want a proper match.  Need to restore the
-			 * subexpr if we had a match, because they may have
-			 * been set. */
-			if (status == RA_MATCH)
-			{
-			    status = RA_NOMATCH;
-			    restore_subexpr(((regbehind_T *)rp) - 1);
-			}
-		    }
-		    regstack_pop(&scan);
-		    regstack.ga_len -= sizeof(regbehind_T);
-		}
-	    }
-	    break;
-
-	  case RS_STAR_LONG:
-	  case RS_STAR_SHORT:
-	    {
-		regstar_T	    *rst = ((regstar_T *)rp) - 1;
-
-		if (status == RA_MATCH)
-		{
-		    regstack_pop(&scan);
-		    regstack.ga_len -= sizeof(regstar_T);
-		    break;
-		}
-
-		/* Tried once already, restore input pointers. */
-		if (status != RA_BREAK)
-		    reg_restore(&rp->rs_un.regsave, &backpos);
-
-		/* Repeat until we found a position where it could match. */
-		for (;;)
-		{
-		    if (status != RA_BREAK)
-		    {
-			/* Tried first position already, advance. */
-			if (rp->rs_state == RS_STAR_LONG)
-			{
-			    /* Trying for longest match, but couldn't or
-			     * didn't match -- back up one char. */
-			    if (--rst->count < rst->minval)
-				break;
-			    if (rex.input == rex.line)
-			    {
-				/* backup to last char of previous line */
-				--rex.lnum;
-				rex.line = reg_getline(rex.lnum);
-				/* Just in case regrepeat() didn't count
-				 * right. */
-				if (rex.line == NULL)
-				    break;
-				rex.input = rex.line + STRLEN(rex.line);
-				fast_breakcheck();
-			    }
-			    else
-				MB_PTR_BACK(rex.line, rex.input);
-			}
-			else
-			{
-			    /* Range is backwards, use shortest match first.
-			     * Careful: maxval and minval are exchanged!
-			     * Couldn't or didn't match: try advancing one
-			     * char. */
-			    if (rst->count == rst->minval
-				  || regrepeat(OPERAND(rp->rs_scan), 1L) == 0)
-				break;
-			    ++rst->count;
-			}
-			if (got_int)
-			    break;
-		    }
-		    else
-			status = RA_NOMATCH;
-
-		    /* If it could match, try it. */
-		    if (rst->nextb == NUL || *rex.input == rst->nextb
-					     || *rex.input == rst->nextb_ic)
-		    {
-			reg_save(&rp->rs_un.regsave, &backpos);
-			scan = regnext(rp->rs_scan);
-			status = RA_CONT;
-			break;
-		    }
-		}
-		if (status != RA_CONT)
-		{
-		    /* Failed. */
-		    regstack_pop(&scan);
-		    regstack.ga_len -= sizeof(regstar_T);
-		    status = RA_NOMATCH;
-		}
-	    }
-	    break;
-	}
-
-	/* If we want to continue the inner loop or didn't pop a state
-	 * continue matching loop */
-	if (status == RA_CONT || rp == (regitem_T *)
-			     ((char *)regstack.ga_data + regstack.ga_len) - 1)
-	    break;
-    }
-
-    /* May need to continue with the inner loop, starting at "scan". */
-    if (status == RA_CONT)
-	continue;
-
-    /*
-     * If the regstack is empty or something failed we are done.
-     */
-    if (regstack.ga_len == 0 || status == RA_FAIL)
-    {
-	if (scan == NULL)
-	{
-	    /*
-	     * We get here only if there's trouble -- normally "case END" is
-	     * the terminating point.
-	     */
-	    emsg(_(e_re_corr));
-#ifdef DEBUG
-	    printf("Premature EOL\n");
-#endif
-	}
-	return (status == RA_MATCH);
-    }
-
-  } /* End of loop until the regstack is empty. */
-
-  /* NOTREACHED */
-}
-
-/*
- * Push an item onto the regstack.
- * Returns pointer to new item.  Returns NULL when out of memory.
- */
-    static regitem_T *
-regstack_push(regstate_T state, char_u *scan)
-{
-    regitem_T	*rp;
-
-    if ((long)((unsigned)regstack.ga_len >> 10) >= p_mmp)
-    {
-	emsg(_(e_maxmempat));
-	return NULL;
-    }
-    if (ga_grow(&regstack, sizeof(regitem_T)) == FAIL)
-	return NULL;
-
-    rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len);
-    rp->rs_state = state;
-    rp->rs_scan = scan;
-
-    regstack.ga_len += sizeof(regitem_T);
-    return rp;
-}
-
-/*
- * Pop an item from the regstack.
- */
-    static void
-regstack_pop(char_u **scan)
-{
-    regitem_T	*rp;
-
-    rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len) - 1;
-    *scan = rp->rs_scan;
-
-    regstack.ga_len -= sizeof(regitem_T);
-}
-
-/*
- * regrepeat - repeatedly match something simple, return how many.
- * Advances rex.input (and rex.lnum) to just after the matched chars.
- */
-    static int
-regrepeat(
-    char_u	*p,
-    long	maxcount)   /* maximum number of matches allowed */
-{
-    long	count = 0;
-    char_u	*scan;
-    char_u	*opnd;
-    int		mask;
-    int		testval = 0;
-
-    scan = rex.input;	    /* Make local copy of rex.input for speed. */
-    opnd = OPERAND(p);
-    switch (OP(p))
-    {
-      case ANY:
-      case ANY + ADD_NL:
-	while (count < maxcount)
-	{
-	    /* Matching anything means we continue until end-of-line (or
-	     * end-of-file for ANY + ADD_NL), only limited by maxcount. */
-	    while (*scan != NUL && count < maxcount)
-	    {
-		++count;
-		MB_PTR_ADV(scan);
-	    }
-	    if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
-				      || rex.reg_line_lbr || count == maxcount)
-		break;
-	    ++count;		/* count the line-break */
-	    reg_nextline();
-	    scan = rex.input;
-	    if (got_int)
-		break;
-	}
-	break;
-
-      case IDENT:
-      case IDENT + ADD_NL:
-	testval = TRUE;
-	/* FALLTHROUGH */
-      case SIDENT:
-      case SIDENT + ADD_NL:
-	while (count < maxcount)
-	{
-	    if (vim_isIDc(PTR2CHAR(scan)) && (testval || !VIM_ISDIGIT(*scan)))
-	    {
-		MB_PTR_ADV(scan);
-	    }
-	    else if (*scan == NUL)
-	    {
-		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
-							   || rex.reg_line_lbr)
-		    break;
-		reg_nextline();
-		scan = rex.input;
-		if (got_int)
-		    break;
-	    }
-	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
-		++scan;
-	    else
-		break;
-	    ++count;
-	}
-	break;
-
-      case KWORD:
-      case KWORD + ADD_NL:
-	testval = TRUE;
-	/* FALLTHROUGH */
-      case SKWORD:
-      case SKWORD + ADD_NL:
-	while (count < maxcount)
-	{
-	    if (vim_iswordp_buf(scan, rex.reg_buf)
-					  && (testval || !VIM_ISDIGIT(*scan)))
-	    {
-		MB_PTR_ADV(scan);
-	    }
-	    else if (*scan == NUL)
-	    {
-		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
-							   || rex.reg_line_lbr)
-		    break;
-		reg_nextline();
-		scan = rex.input;
-		if (got_int)
-		    break;
-	    }
-	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
-		++scan;
-	    else
-		break;
-	    ++count;
-	}
-	break;
-
-      case FNAME:
-      case FNAME + ADD_NL:
-	testval = TRUE;
-	/* FALLTHROUGH */
-      case SFNAME:
-      case SFNAME + ADD_NL:
-	while (count < maxcount)
-	{
-	    if (vim_isfilec(PTR2CHAR(scan)) && (testval || !VIM_ISDIGIT(*scan)))
-	    {
-		MB_PTR_ADV(scan);
-	    }
-	    else if (*scan == NUL)
-	    {
-		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
-							   || rex.reg_line_lbr)
-		    break;
-		reg_nextline();
-		scan = rex.input;
-		if (got_int)
-		    break;
-	    }
-	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
-		++scan;
-	    else
-		break;
-	    ++count;
-	}
-	break;
-
-      case PRINT:
-      case PRINT + ADD_NL:
-	testval = TRUE;
-	/* FALLTHROUGH */
-      case SPRINT:
-      case SPRINT + ADD_NL:
-	while (count < maxcount)
-	{
-	    if (*scan == NUL)
-	    {
-		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
-							   || rex.reg_line_lbr)
-		    break;
-		reg_nextline();
-		scan = rex.input;
-		if (got_int)
-		    break;
-	    }
-	    else if (vim_isprintc(PTR2CHAR(scan)) == 1
-					  && (testval || !VIM_ISDIGIT(*scan)))
-	    {
-		MB_PTR_ADV(scan);
-	    }
-	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
-		++scan;
-	    else
-		break;
-	    ++count;
-	}
-	break;
-
-      case WHITE:
-      case WHITE + ADD_NL:
-	testval = mask = RI_WHITE;
-do_class:
-	while (count < maxcount)
-	{
-	    int		l;
-
-	    if (*scan == NUL)
-	    {
-		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
-							   || rex.reg_line_lbr)
-		    break;
-		reg_nextline();
-		scan = rex.input;
-		if (got_int)
-		    break;
-	    }
-	    else if (has_mbyte && (l = (*mb_ptr2len)(scan)) > 1)
-	    {
-		if (testval != 0)
-		    break;
-		scan += l;
-	    }
-	    else if ((class_tab[*scan] & mask) == testval)
-		++scan;
-	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
-		++scan;
-	    else
-		break;
-	    ++count;
-	}
-	break;
-
-      case NWHITE:
-      case NWHITE + ADD_NL:
-	mask = RI_WHITE;
-	goto do_class;
-      case DIGIT:
-      case DIGIT + ADD_NL:
-	testval = mask = RI_DIGIT;
-	goto do_class;
-      case NDIGIT:
-      case NDIGIT + ADD_NL:
-	mask = RI_DIGIT;
-	goto do_class;
-      case HEX:
-      case HEX + ADD_NL:
-	testval = mask = RI_HEX;
-	goto do_class;
-      case NHEX:
-      case NHEX + ADD_NL:
-	mask = RI_HEX;
-	goto do_class;
-      case OCTAL:
-      case OCTAL + ADD_NL:
-	testval = mask = RI_OCTAL;
-	goto do_class;
-      case NOCTAL:
-      case NOCTAL + ADD_NL:
-	mask = RI_OCTAL;
-	goto do_class;
-      case WORD:
-      case WORD + ADD_NL:
-	testval = mask = RI_WORD;
-	goto do_class;
-      case NWORD:
-      case NWORD + ADD_NL:
-	mask = RI_WORD;
-	goto do_class;
-      case HEAD:
-      case HEAD + ADD_NL:
-	testval = mask = RI_HEAD;
-	goto do_class;
-      case NHEAD:
-      case NHEAD + ADD_NL:
-	mask = RI_HEAD;
-	goto do_class;
-      case ALPHA:
-      case ALPHA + ADD_NL:
-	testval = mask = RI_ALPHA;
-	goto do_class;
-      case NALPHA:
-      case NALPHA + ADD_NL:
-	mask = RI_ALPHA;
-	goto do_class;
-      case LOWER:
-      case LOWER + ADD_NL:
-	testval = mask = RI_LOWER;
-	goto do_class;
-      case NLOWER:
-      case NLOWER + ADD_NL:
-	mask = RI_LOWER;
-	goto do_class;
-      case UPPER:
-      case UPPER + ADD_NL:
-	testval = mask = RI_UPPER;
-	goto do_class;
-      case NUPPER:
-      case NUPPER + ADD_NL:
-	mask = RI_UPPER;
-	goto do_class;
-
-      case EXACTLY:
-	{
-	    int	    cu, cl;
-
-	    /* This doesn't do a multi-byte character, because a MULTIBYTECODE
-	     * would have been used for it.  It does handle single-byte
-	     * characters, such as latin1. */
-	    if (rex.reg_ic)
-	    {
-		cu = MB_TOUPPER(*opnd);
-		cl = MB_TOLOWER(*opnd);
-		while (count < maxcount && (*scan == cu || *scan == cl))
-		{
-		    count++;
-		    scan++;
-		}
-	    }
-	    else
-	    {
-		cu = *opnd;
-		while (count < maxcount && *scan == cu)
-		{
-		    count++;
-		    scan++;
-		}
-	    }
-	    break;
-	}
-
-      case MULTIBYTECODE:
-	{
-	    int		i, len, cf = 0;
-
-	    /* Safety check (just in case 'encoding' was changed since
-	     * compiling the program). */
-	    if ((len = (*mb_ptr2len)(opnd)) > 1)
-	    {
-		if (rex.reg_ic && enc_utf8)
-		    cf = utf_fold(utf_ptr2char(opnd));
-		while (count < maxcount && (*mb_ptr2len)(scan) >= len)
-		{
-		    for (i = 0; i < len; ++i)
-			if (opnd[i] != scan[i])
-			    break;
-		    if (i < len && (!rex.reg_ic || !enc_utf8
-					|| utf_fold(utf_ptr2char(scan)) != cf))
-			break;
-		    scan += len;
-		    ++count;
-		}
-	    }
-	}
-	break;
-
-      case ANYOF:
-      case ANYOF + ADD_NL:
-	testval = TRUE;
-	/* FALLTHROUGH */
-
-      case ANYBUT:
-      case ANYBUT + ADD_NL:
-	while (count < maxcount)
-	{
-	    int len;
-
-	    if (*scan == NUL)
-	    {
-		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
-							   || rex.reg_line_lbr)
-		    break;
-		reg_nextline();
-		scan = rex.input;
-		if (got_int)
-		    break;
-	    }
-	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
-		++scan;
-	    else if (has_mbyte && (len = (*mb_ptr2len)(scan)) > 1)
-	    {
-		if ((cstrchr(opnd, (*mb_ptr2char)(scan)) == NULL) == testval)
-		    break;
-		scan += len;
-	    }
-	    else
-	    {
-		if ((cstrchr(opnd, *scan) == NULL) == testval)
-		    break;
-		++scan;
-	    }
-	    ++count;
-	}
-	break;
-
-      case NEWL:
-	while (count < maxcount
-		&& ((*scan == NUL && rex.lnum <= rex.reg_maxline
-				       && !rex.reg_line_lbr && REG_MULTI)
-		    || (*scan == '\n' && rex.reg_line_lbr)))
-	{
-	    count++;
-	    if (rex.reg_line_lbr)
-		ADVANCE_REGINPUT();
-	    else
-		reg_nextline();
-	    scan = rex.input;
-	    if (got_int)
-		break;
-	}
-	break;
-
-      default:			/* Oh dear.  Called inappropriately. */
-	emsg(_(e_re_corr));
-#ifdef DEBUG
-	printf("Called regrepeat with op code %d\n", OP(p));
-#endif
-	break;
-    }
-
-    rex.input = scan;
-
-    return (int)count;
-}
-
-/*
- * regnext - dig the "next" pointer out of a node
- * Returns NULL when calculating size, when there is no next item and when
- * there is an error.
- */
-    static char_u *
-regnext(char_u *p)
-{
-    int	    offset;
-
-    if (p == JUST_CALC_SIZE || reg_toolong)
-	return NULL;
-
-    offset = NEXT(p);
-    if (offset == 0)
-	return NULL;
-
-    if (OP(p) == BACK)
-	return p - offset;
-    else
-	return p + offset;
-}
-
 /*
  * Check the regexp program for its magic number.
  * Return TRUE if it's wrong.
@@ -6182,64 +1370,6 @@ cleanup_zsubexpr(void)
 #endif
 
 /*
- * Save the current subexpr to "bp", so that they can be restored
- * later by restore_subexpr().
- */
-    static void
-save_subexpr(regbehind_T *bp)
-{
-    int i;
-
-    /* When "rex.need_clear_subexpr" is set we don't need to save the values, only
-     * remember that this flag needs to be set again when restoring. */
-    bp->save_need_clear_subexpr = rex.need_clear_subexpr;
-    if (!rex.need_clear_subexpr)
-    {
-	for (i = 0; i < NSUBEXP; ++i)
-	{
-	    if (REG_MULTI)
-	    {
-		bp->save_start[i].se_u.pos = rex.reg_startpos[i];
-		bp->save_end[i].se_u.pos = rex.reg_endpos[i];
-	    }
-	    else
-	    {
-		bp->save_start[i].se_u.ptr = rex.reg_startp[i];
-		bp->save_end[i].se_u.ptr = rex.reg_endp[i];
-	    }
-	}
-    }
-}
-
-/*
- * Restore the subexpr from "bp".
- */
-    static void
-restore_subexpr(regbehind_T *bp)
-{
-    int i;
-
-    /* Only need to restore saved values when they are not to be cleared. */
-    rex.need_clear_subexpr = bp->save_need_clear_subexpr;
-    if (!rex.need_clear_subexpr)
-    {
-	for (i = 0; i < NSUBEXP; ++i)
-	{
-	    if (REG_MULTI)
-	    {
-		rex.reg_startpos[i] = bp->save_start[i].se_u.pos;
-		rex.reg_endpos[i] = bp->save_end[i].se_u.pos;
-	    }
-	    else
-	    {
-		rex.reg_startp[i] = bp->save_start[i].se_u.ptr;
-		rex.reg_endp[i] = bp->save_end[i].se_u.ptr;
-	    }
-	}
-    }
-}
-
-/*
  * Advance rex.lnum, rex.line and rex.input to the next line.
  */
     static void
@@ -6251,93 +1381,6 @@ reg_nextline(void)
 }
 
 /*
- * Save the input line and position in a regsave_T.
- */
-    static void
-reg_save(regsave_T *save, garray_T *gap)
-{
-    if (REG_MULTI)
-    {
-	save->rs_u.pos.col = (colnr_T)(rex.input - rex.line);
-	save->rs_u.pos.lnum = rex.lnum;
-    }
-    else
-	save->rs_u.ptr = rex.input;
-    save->rs_len = gap->ga_len;
-}
-
-/*
- * Restore the input line and position from a regsave_T.
- */
-    static void
-reg_restore(regsave_T *save, garray_T *gap)
-{
-    if (REG_MULTI)
-    {
-	if (rex.lnum != save->rs_u.pos.lnum)
-	{
-	    /* only call reg_getline() when the line number changed to save
-	     * a bit of time */
-	    rex.lnum = save->rs_u.pos.lnum;
-	    rex.line = reg_getline(rex.lnum);
-	}
-	rex.input = rex.line + save->rs_u.pos.col;
-    }
-    else
-	rex.input = save->rs_u.ptr;
-    gap->ga_len = save->rs_len;
-}
-
-/*
- * Return TRUE if current position is equal to saved position.
- */
-    static int
-reg_save_equal(regsave_T *save)
-{
-    if (REG_MULTI)
-	return rex.lnum == save->rs_u.pos.lnum
-				  && rex.input == rex.line + save->rs_u.pos.col;
-    return rex.input == save->rs_u.ptr;
-}
-
-/*
- * Tentatively set the sub-expression start to the current position (after
- * calling regmatch() they will have changed).  Need to save the existing
- * values for when there is no match.
- * Use se_save() to use pointer (save_se_multi()) or position (save_se_one()),
- * depending on REG_MULTI.
- */
-    static void
-save_se_multi(save_se_T *savep, lpos_T *posp)
-{
-    savep->se_u.pos = *posp;
-    posp->lnum = rex.lnum;
-    posp->col = (colnr_T)(rex.input - rex.line);
-}
-
-    static void
-save_se_one(save_se_T *savep, char_u **pp)
-{
-    savep->se_u.ptr = *pp;
-    *pp = rex.input;
-}
-
-/*
- * Compare a number with the operand of RE_LNUM, RE_COL or RE_VCOL.
- */
-    static int
-re_num_cmp(long_u val, char_u *scan)
-{
-    long_u  n = OPERAND_MIN(scan);
-
-    if (OPERAND_CMP(scan) == '>')
-	return val > n;
-    if (OPERAND_CMP(scan) == '<')
-	return val < n;
-    return val == n;
-}
-
-/*
  * Check whether a backreference matches.
  * Returns RA_FAIL, RA_NOMATCH or RA_MATCH.
  * If "bytelen" is not NULL, it is set to the byte length of the match in the
@@ -6410,477 +1453,6 @@ match_with_backref(
     return RA_MATCH;
 }
 
-#ifdef BT_REGEXP_DUMP
-
-/*
- * regdump - dump a regexp onto stdout in vaguely comprehensible form
- */
-    static void
-regdump(char_u *pattern, bt_regprog_T *r)
-{
-    char_u  *s;
-    int	    op = EXACTLY;	/* Arbitrary non-END op. */
-    char_u  *next;
-    char_u  *end = NULL;
-    FILE    *f;
-
-#ifdef BT_REGEXP_LOG
-    f = fopen("bt_regexp_log.log", "a");
-#else
-    f = stdout;
-#endif
-    if (f == NULL)
-	return;
-    fprintf(f, "-------------------------------------\n\r\nregcomp(%s):\r\n", pattern);
-
-    s = r->program + 1;
-    /*
-     * Loop until we find the END that isn't before a referred next (an END
-     * can also appear in a NOMATCH operand).
-     */
-    while (op != END || s <= end)
-    {
-	op = OP(s);
-	fprintf(f, "%2d%s", (int)(s - r->program), regprop(s)); /* Where, what. */
-	next = regnext(s);
-	if (next == NULL)	/* Next ptr. */
-	    fprintf(f, "(0)");
-	else
-	    fprintf(f, "(%d)", (int)((s - r->program) + (next - s)));
-	if (end < next)
-	    end = next;
-	if (op == BRACE_LIMITS)
-	{
-	    /* Two ints */
-	    fprintf(f, " minval %ld, maxval %ld", OPERAND_MIN(s), OPERAND_MAX(s));
-	    s += 8;
-	}
-	else if (op == BEHIND || op == NOBEHIND)
-	{
-	    /* one int */
-	    fprintf(f, " count %ld", OPERAND_MIN(s));
-	    s += 4;
-	}
-	else if (op == RE_LNUM || op == RE_COL || op == RE_VCOL)
-	{
-	    /* one int plus comparator */
-	    fprintf(f, " count %ld", OPERAND_MIN(s));
-	    s += 5;
-	}
-	s += 3;
-	if (op == ANYOF || op == ANYOF + ADD_NL
-		|| op == ANYBUT || op == ANYBUT + ADD_NL
-		|| op == EXACTLY)
-	{
-	    /* Literal string, where present. */
-	    fprintf(f, "\nxxxxxxxxx\n");
-	    while (*s != NUL)
-		fprintf(f, "%c", *s++);
-	    fprintf(f, "\nxxxxxxxxx\n");
-	    s++;
-	}
-	fprintf(f, "\r\n");
-    }
-
-    /* Header fields of interest. */
-    if (r->regstart != NUL)
-	fprintf(f, "start `%s' 0x%x; ", r->regstart < 256
-		? (char *)transchar(r->regstart)
-		: "multibyte", r->regstart);
-    if (r->reganch)
-	fprintf(f, "anchored; ");
-    if (r->regmust != NULL)
-	fprintf(f, "must have \"%s\"", r->regmust);
-    fprintf(f, "\r\n");
-
-#ifdef BT_REGEXP_LOG
-    fclose(f);
-#endif
-}
-#endif	    /* BT_REGEXP_DUMP */
-
-#ifdef DEBUG
-/*
- * regprop - printable representation of opcode
- */
-    static char_u *
-regprop(char_u *op)
-{
-    char	    *p;
-    static char	    buf[50];
-
-    STRCPY(buf, ":");
-
-    switch ((int) OP(op))
-    {
-      case BOL:
-	p = "BOL";
-	break;
-      case EOL:
-	p = "EOL";
-	break;
-      case RE_BOF:
-	p = "BOF";
-	break;
-      case RE_EOF:
-	p = "EOF";
-	break;
-      case CURSOR:
-	p = "CURSOR";
-	break;
-      case RE_VISUAL:
-	p = "RE_VISUAL";
-	break;
-      case RE_LNUM:
-	p = "RE_LNUM";
-	break;
-      case RE_MARK:
-	p = "RE_MARK";
-	break;
-      case RE_COL:
-	p = "RE_COL";
-	break;
-      case RE_VCOL:
-	p = "RE_VCOL";
-	break;
-      case BOW:
-	p = "BOW";
-	break;
-      case EOW:
-	p = "EOW";
-	break;
-      case ANY:
-	p = "ANY";
-	break;
-      case ANY + ADD_NL:
-	p = "ANY+NL";
-	break;
-      case ANYOF:
-	p = "ANYOF";
-	break;
-      case ANYOF + ADD_NL:
-	p = "ANYOF+NL";
-	break;
-      case ANYBUT:
-	p = "ANYBUT";
-	break;
-      case ANYBUT + ADD_NL:
-	p = "ANYBUT+NL";
-	break;
-      case IDENT:
-	p = "IDENT";
-	break;
-      case IDENT + ADD_NL:
-	p = "IDENT+NL";
-	break;
-      case SIDENT:
-	p = "SIDENT";
-	break;
-      case SIDENT + ADD_NL:
-	p = "SIDENT+NL";
-	break;
-      case KWORD:
-	p = "KWORD";
-	break;
-      case KWORD + ADD_NL:
-	p = "KWORD+NL";
-	break;
-      case SKWORD:
-	p = "SKWORD";
-	break;
-      case SKWORD + ADD_NL:
-	p = "SKWORD+NL";
-	break;
-      case FNAME:
-	p = "FNAME";
-	break;
-      case FNAME + ADD_NL:
-	p = "FNAME+NL";
-	break;
-      case SFNAME:
-	p = "SFNAME";
-	break;
-      case SFNAME + ADD_NL:
-	p = "SFNAME+NL";
-	break;
-      case PRINT:
-	p = "PRINT";
-	break;
-      case PRINT + ADD_NL:
-	p = "PRINT+NL";
-	break;
-      case SPRINT:
-	p = "SPRINT";
-	break;
-      case SPRINT + ADD_NL:
-	p = "SPRINT+NL";
-	break;
-      case WHITE:
-	p = "WHITE";
-	break;
-      case WHITE + ADD_NL:
-	p = "WHITE+NL";
-	break;
-      case NWHITE:
-	p = "NWHITE";
-	break;
-      case NWHITE + ADD_NL:
-	p = "NWHITE+NL";
-	break;
-      case DIGIT:
-	p = "DIGIT";
-	break;
-      case DIGIT + ADD_NL:
-	p = "DIGIT+NL";
-	break;
-      case NDIGIT:
-	p = "NDIGIT";
-	break;
-      case NDIGIT + ADD_NL:
-	p = "NDIGIT+NL";
-	break;
-      case HEX:
-	p = "HEX";
-	break;
-      case HEX + ADD_NL:
-	p = "HEX+NL";
-	break;
-      case NHEX:
-	p = "NHEX";
-	break;
-      case NHEX + ADD_NL:
-	p = "NHEX+NL";
-	break;
-      case OCTAL:
-	p = "OCTAL";
-	break;
-      case OCTAL + ADD_NL:
-	p = "OCTAL+NL";
-	break;
-      case NOCTAL:
-	p = "NOCTAL";
-	break;
-      case NOCTAL + ADD_NL:
-	p = "NOCTAL+NL";
-	break;
-      case WORD:
-	p = "WORD";
-	break;
-      case WORD + ADD_NL:
-	p = "WORD+NL";
-	break;
-      case NWORD:
-	p = "NWORD";
-	break;
-      case NWORD + ADD_NL:
-	p = "NWORD+NL";
-	break;
-      case HEAD:
-	p = "HEAD";
-	break;
-      case HEAD + ADD_NL:
-	p = "HEAD+NL";
-	break;
-      case NHEAD:
-	p = "NHEAD";
-	break;
-      case NHEAD + ADD_NL:
-	p = "NHEAD+NL";
-	break;
-      case ALPHA:
-	p = "ALPHA";
-	break;
-      case ALPHA + ADD_NL:
-	p = "ALPHA+NL";
-	break;
-      case NALPHA:
-	p = "NALPHA";
-	break;
-      case NALPHA + ADD_NL:
-	p = "NALPHA+NL";
-	break;
-      case LOWER:
-	p = "LOWER";
-	break;
-      case LOWER + ADD_NL:
-	p = "LOWER+NL";
-	break;
-      case NLOWER:
-	p = "NLOWER";
-	break;
-      case NLOWER + ADD_NL:
-	p = "NLOWER+NL";
-	break;
-      case UPPER:
-	p = "UPPER";
-	break;
-      case UPPER + ADD_NL:
-	p = "UPPER+NL";
-	break;
-      case NUPPER:
-	p = "NUPPER";
-	break;
-      case NUPPER + ADD_NL:
-	p = "NUPPER+NL";
-	break;
-      case BRANCH:
-	p = "BRANCH";
-	break;
-      case EXACTLY:
-	p = "EXACTLY";
-	break;
-      case NOTHING:
-	p = "NOTHING";
-	break;
-      case BACK:
-	p = "BACK";
-	break;
-      case END:
-	p = "END";
-	break;
-      case MOPEN + 0:
-	p = "MATCH START";
-	break;
-      case MOPEN + 1:
-      case MOPEN + 2:
-      case MOPEN + 3:
-      case MOPEN + 4:
-      case MOPEN + 5:
-      case MOPEN + 6:
-      case MOPEN + 7:
-      case MOPEN + 8:
-      case MOPEN + 9:
-	sprintf(buf + STRLEN(buf), "MOPEN%d", OP(op) - MOPEN);
-	p = NULL;
-	break;
-      case MCLOSE + 0:
-	p = "MATCH END";
-	break;
-      case MCLOSE + 1:
-      case MCLOSE + 2:
-      case MCLOSE + 3:
-      case MCLOSE + 4:
-      case MCLOSE + 5:
-      case MCLOSE + 6:
-      case MCLOSE + 7:
-      case MCLOSE + 8:
-      case MCLOSE + 9:
-	sprintf(buf + STRLEN(buf), "MCLOSE%d", OP(op) - MCLOSE);
-	p = NULL;
-	break;
-      case BACKREF + 1:
-      case BACKREF + 2:
-      case BACKREF + 3:
-      case BACKREF + 4:
-      case BACKREF + 5:
-      case BACKREF + 6:
-      case BACKREF + 7:
-      case BACKREF + 8:
-      case BACKREF + 9:
-	sprintf(buf + STRLEN(buf), "BACKREF%d", OP(op) - BACKREF);
-	p = NULL;
-	break;
-      case NOPEN:
-	p = "NOPEN";
-	break;
-      case NCLOSE:
-	p = "NCLOSE";
-	break;
-#ifdef FEAT_SYN_HL
-      case ZOPEN + 1:
-      case ZOPEN + 2:
-      case ZOPEN + 3:
-      case ZOPEN + 4:
-      case ZOPEN + 5:
-      case ZOPEN + 6:
-      case ZOPEN + 7:
-      case ZOPEN + 8:
-      case ZOPEN + 9:
-	sprintf(buf + STRLEN(buf), "ZOPEN%d", OP(op) - ZOPEN);
-	p = NULL;
-	break;
-      case ZCLOSE + 1:
-      case ZCLOSE + 2:
-      case ZCLOSE + 3:
-      case ZCLOSE + 4:
-      case ZCLOSE + 5:
-      case ZCLOSE + 6:
-      case ZCLOSE + 7:
-      case ZCLOSE + 8:
-      case ZCLOSE + 9:
-	sprintf(buf + STRLEN(buf), "ZCLOSE%d", OP(op) - ZCLOSE);
-	p = NULL;
-	break;
-      case ZREF + 1:
-      case ZREF + 2:
-      case ZREF + 3:
-      case ZREF + 4:
-      case ZREF + 5:
-      case ZREF + 6:
-      case ZREF + 7:
-      case ZREF + 8:
-      case ZREF + 9:
-	sprintf(buf + STRLEN(buf), "ZREF%d", OP(op) - ZREF);
-	p = NULL;
-	break;
-#endif
-      case STAR:
-	p = "STAR";
-	break;
-      case PLUS:
-	p = "PLUS";
-	break;
-      case NOMATCH:
-	p = "NOMATCH";
-	break;
-      case MATCH:
-	p = "MATCH";
-	break;
-      case BEHIND:
-	p = "BEHIND";
-	break;
-      case NOBEHIND:
-	p = "NOBEHIND";
-	break;
-      case SUBPAT:
-	p = "SUBPAT";
-	break;
-      case BRACE_LIMITS:
-	p = "BRACE_LIMITS";
-	break;
-      case BRACE_SIMPLE:
-	p = "BRACE_SIMPLE";
-	break;
-      case BRACE_COMPLEX + 0:
-      case BRACE_COMPLEX + 1:
-      case BRACE_COMPLEX + 2:
-      case BRACE_COMPLEX + 3:
-      case BRACE_COMPLEX + 4:
-      case BRACE_COMPLEX + 5:
-      case BRACE_COMPLEX + 6:
-      case BRACE_COMPLEX + 7:
-      case BRACE_COMPLEX + 8:
-      case BRACE_COMPLEX + 9:
-	sprintf(buf + STRLEN(buf), "BRACE_COMPLEX%d", OP(op) - BRACE_COMPLEX);
-	p = NULL;
-	break;
-      case MULTIBYTECODE:
-	p = "MULTIBYTECODE";
-	break;
-      case NEWL:
-	p = "NEWL";
-	break;
-      default:
-	sprintf(buf + STRLEN(buf), "corrupt %d", OP(op));
-	p = NULL;
-	break;
-    }
-    if (p != NULL)
-	STRCAT(buf, p);
-    return (char_u *)buf;
-}
-#endif	    /* DEBUG */
-
 /*
  * Used in a place where no * or \+ can follow.
  */
@@ -7006,12 +1578,11 @@ cstrncmp(char_u *s1, char_u *s2, int *n)
 	    c1 = mb_ptr2char_adv(&str1);
 	    c2 = mb_ptr2char_adv(&str2);
 
-	    /* decompose the character if necessary, into 'base' characters
-	     * because I don't care about Arabic, I will hard-code the Hebrew
-	     * which I *do* care about!  So sue me... */
+	    // Decompose the character if necessary, into 'base' characters.
+	    // Currently hard-coded for Hebrew, Arabic to be done...
 	    if (c1 != c2 && (!rex.reg_ic || utf_fold(c1) != utf_fold(c2)))
 	    {
-		/* decomposition necessary? */
+		// decomposition necessary?
 		mb_decompose(c1, &c11, &junk, &junk);
 		mb_decompose(c2, &c12, &junk, &junk);
 		c1 = c11;
@@ -7933,6 +2504,8 @@ reg_submatch_list(int no)
 }
 #endif
 
+#include "regexp_bt.c"
+
 static regengine_T bt_regengine =
 {
     bt_regcomp,
@@ -8073,6 +2646,17 @@ vim_regfree(regprog_T *prog)
 	prog->engine->regfree(prog);
 }
 
+#if defined(EXITFREE) || defined(PROTO)
+    void
+free_regexp_stuff(void)
+{
+    ga_clear(&regstack);
+    ga_clear(&backpos);
+    vim_free(reg_tofree);
+    vim_free(reg_prev_sub);
+}
+#endif
+
 #ifdef FEAT_EVAL
     static void
 report_re_switch(char_u *pat)
new file mode 100644
--- /dev/null
+++ b/src/regexp_bt.c
@@ -0,0 +1,5381 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * Backtracking regular expression implementation.
+ *
+ * This file is included in "regexp.c".
+ *
+ * NOTICE:
+ *
+ * This is NOT the original regular expression code as written by Henry
+ * Spencer.  This code has been modified specifically for use with the VIM
+ * editor, and should not be used separately from Vim.  If you want a good
+ * regular expression library, get the original code.  The copyright notice
+ * that follows is from the original.
+ *
+ * END NOTICE
+ *
+ *	Copyright (c) 1986 by University of Toronto.
+ *	Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *	Permission is granted to anyone to use this software for any
+ *	purpose on any computer system, and to redistribute it freely,
+ *	subject to the following restrictions:
+ *
+ *	1. The author is not responsible for the consequences of use of
+ *		this software, no matter how awful, even if they arise
+ *		from defects in it.
+ *
+ *	2. The origin of this software must not be misrepresented, either
+ *		by explicit claim or by omission.
+ *
+ *	3. Altered versions must be plainly marked as such, and must not
+ *		be misrepresented as being the original software.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions.  Serious changes in
+ * regular-expression syntax might require a total rethink.
+ *
+ * Changes have been made by Tony Andrews, Olaf 'Rhialto' Seibert, Robert
+ * Webb, Ciaran McCreesh and Bram Moolenaar.
+ * Named character class support added by Walter Briscoe (1998 Jul 01)
+ */
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases.  They are:
+ *
+ * regstart	char that must begin a match; NUL if none obvious; Can be a
+ *		multi-byte character.
+ * reganch	is the match anchored (at beginning-of-line only)?
+ * regmust	string (pointer into program) that match must include, or NULL
+ * regmlen	length of regmust string
+ * regflags	RF_ values or'ed together
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot.  Regmust permits fast rejection
+ * of lines that cannot possibly match.  The regmust tests are costly enough
+ * that vim_regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
+ * supplied because the test in vim_regexec() needs it and vim_regcomp() is
+ * computing it anyway.
+ */
+
+/*
+ * Structure for regexp "program".  This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology).  Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
+ * all nodes except BRANCH and BRACES_COMPLEX implement concatenation; a "next"
+ * pointer with a BRANCH on both ends of it is connecting two alternatives.
+ * (Here we have one of the subtle syntax dependencies:	an individual BRANCH
+ * (as opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence).  The "next" pointer of a BRACES_COMPLEX
+ * node points to the node after the stuff to be repeated.
+ * The operand of some types of node is a literal string; for others, it is a
+ * node leading into a sub-FSM.  In particular, the operand of a BRANCH node
+ * is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects to the
+ * thing following the set of BRANCHes.)
+ *
+ * pattern	is coded like:
+ *
+ *			  +-----------------+
+ *			  |		    V
+ * <aa>\|<bb>	BRANCH <aa> BRANCH <bb> --> END
+ *		     |	    ^	 |	    ^
+ *		     +------+	 +----------+
+ *
+ *
+ *		       +------------------+
+ *		       V		  |
+ * <aa>*	BRANCH BRANCH <aa> --> BACK BRANCH --> NOTHING --> END
+ *		     |	    |		    ^			   ^
+ *		     |	    +---------------+			   |
+ *		     +---------------------------------------------+
+ *
+ *
+ *		       +----------------------+
+ *		       V		      |
+ * <aa>\+	BRANCH <aa> --> BRANCH --> BACK  BRANCH --> NOTHING --> END
+ *		     |		     |		 ^			^
+ *		     |		     +-----------+			|
+ *		     +--------------------------------------------------+
+ *
+ *
+ *					+-------------------------+
+ *					V			  |
+ * <aa>\{}	BRANCH BRACE_LIMITS --> BRACE_COMPLEX <aa> --> BACK  END
+ *		     |				    |		     ^
+ *		     |				    +----------------+
+ *		     +-----------------------------------------------+
+ *
+ *
+ * <aa>\@!<bb>	BRANCH NOMATCH <aa> --> END  <bb> --> END
+ *		     |	     |		      ^       ^
+ *		     |	     +----------------+       |
+ *		     +--------------------------------+
+ *
+ *						      +---------+
+ *						      |		V
+ * \z[abc]	BRANCH BRANCH  a  BRANCH  b  BRANCH  c	BRANCH	NOTHING --> END
+ *		     |	    |	       |	  |	^		    ^
+ *		     |	    |	       |	  +-----+		    |
+ *		     |	    |	       +----------------+		    |
+ *		     |	    +---------------------------+		    |
+ *		     +------------------------------------------------------+
+ *
+ * They all start with a BRANCH for "\|" alternatives, even when there is only
+ * one alternative.
+ */
+
+/*
+ * The opcodes are:
+ */
+
+/* definition	number		   opnd?    meaning */
+#define END		0	/*	End of program or NOMATCH operand. */
+#define BOL		1	/*	Match "" at beginning of line. */
+#define EOL		2	/*	Match "" at end of line. */
+#define BRANCH		3	/* node Match this alternative, or the
+				 *	next... */
+#define BACK		4	/*	Match "", "next" ptr points backward. */
+#define EXACTLY		5	/* str	Match this string. */
+#define NOTHING		6	/*	Match empty string. */
+#define STAR		7	/* node Match this (simple) thing 0 or more
+				 *	times. */
+#define PLUS		8	/* node Match this (simple) thing 1 or more
+				 *	times. */
+#define MATCH		9	/* node match the operand zero-width */
+#define NOMATCH		10	/* node check for no match with operand */
+#define BEHIND		11	/* node look behind for a match with operand */
+#define NOBEHIND	12	/* node look behind for no match with operand */
+#define SUBPAT		13	/* node match the operand here */
+#define BRACE_SIMPLE	14	/* node Match this (simple) thing between m and
+				 *	n times (\{m,n\}). */
+#define BOW		15	/*	Match "" after [^a-zA-Z0-9_] */
+#define EOW		16	/*	Match "" at    [^a-zA-Z0-9_] */
+#define BRACE_LIMITS	17	/* nr nr  define the min & max for BRACE_SIMPLE
+				 *	and BRACE_COMPLEX. */
+#define NEWL		18	/*	Match line-break */
+#define BHPOS		19	/*	End position for BEHIND or NOBEHIND */
+
+
+/* character classes: 20-48 normal, 50-78 include a line-break */
+#define ADD_NL		30
+#define FIRST_NL	ANY + ADD_NL
+#define ANY		20	/*	Match any one character. */
+#define ANYOF		21	/* str	Match any character in this string. */
+#define ANYBUT		22	/* str	Match any character not in this
+				 *	string. */
+#define IDENT		23	/*	Match identifier char */
+#define SIDENT		24	/*	Match identifier char but no digit */
+#define KWORD		25	/*	Match keyword char */
+#define SKWORD		26	/*	Match word char but no digit */
+#define FNAME		27	/*	Match file name char */
+#define SFNAME		28	/*	Match file name char but no digit */
+#define PRINT		29	/*	Match printable char */
+#define SPRINT		30	/*	Match printable char but no digit */
+#define WHITE		31	/*	Match whitespace char */
+#define NWHITE		32	/*	Match non-whitespace char */
+#define DIGIT		33	/*	Match digit char */
+#define NDIGIT		34	/*	Match non-digit char */
+#define HEX		35	/*	Match hex char */
+#define NHEX		36	/*	Match non-hex char */
+#define OCTAL		37	/*	Match octal char */
+#define NOCTAL		38	/*	Match non-octal char */
+#define WORD		39	/*	Match word char */
+#define NWORD		40	/*	Match non-word char */
+#define HEAD		41	/*	Match head char */
+#define NHEAD		42	/*	Match non-head char */
+#define ALPHA		43	/*	Match alpha char */
+#define NALPHA		44	/*	Match non-alpha char */
+#define LOWER		45	/*	Match lowercase char */
+#define NLOWER		46	/*	Match non-lowercase char */
+#define UPPER		47	/*	Match uppercase char */
+#define NUPPER		48	/*	Match non-uppercase char */
+#define LAST_NL		NUPPER + ADD_NL
+#define WITH_NL(op)	((op) >= FIRST_NL && (op) <= LAST_NL)
+
+#define MOPEN		80  /* -89	 Mark this point in input as start of
+				 *	 \( subexpr.  MOPEN + 0 marks start of
+				 *	 match. */
+#define MCLOSE		90  /* -99	 Analogous to MOPEN.  MCLOSE + 0 marks
+				 *	 end of match. */
+#define BACKREF		100 /* -109 node Match same string again \1-\9 */
+
+#ifdef FEAT_SYN_HL
+# define ZOPEN		110 /* -119	 Mark this point in input as start of
+				 *	 \z( subexpr. */
+# define ZCLOSE		120 /* -129	 Analogous to ZOPEN. */
+# define ZREF		130 /* -139 node Match external submatch \z1-\z9 */
+#endif
+
+#define BRACE_COMPLEX	140 /* -149 node Match nodes between m & n times */
+
+#define NOPEN		150	/*	Mark this point in input as start of
+					\%( subexpr. */
+#define NCLOSE		151	/*	Analogous to NOPEN. */
+
+#define MULTIBYTECODE	200	/* mbc	Match one multi-byte character */
+#define RE_BOF		201	/*	Match "" at beginning of file. */
+#define RE_EOF		202	/*	Match "" at end of file. */
+#define CURSOR		203	/*	Match location of cursor. */
+
+#define RE_LNUM		204	/* nr cmp  Match line number */
+#define RE_COL		205	/* nr cmp  Match column number */
+#define RE_VCOL		206	/* nr cmp  Match virtual column number */
+
+#define RE_MARK		207	/* mark cmp  Match mark position */
+#define RE_VISUAL	208	/*	Match Visual area */
+#define RE_COMPOSING	209	/* any composing characters */
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH	0x1	/* Known never to match null string. */
+#define SIMPLE		0x2	/* Simple enough to be STAR/PLUS operand. */
+#define SPSTART		0x4	/* Starts with * or +. */
+#define HASNL		0x8	/* Contains some \n. */
+#define HASLOOKBH	0x10	/* Contains "\@<=" or "\@<!". */
+#define WORST		0	/* Worst case. */
+
+static int	num_complex_braces; /* Complex \{...} count */
+static char_u	*regcode;	/* Code-emit pointer, or JUST_CALC_SIZE */
+static long	regsize;	/* Code size. */
+static int	reg_toolong;	/* TRUE when offset out of range */
+static char_u	had_endbrace[NSUBEXP];	/* flags, TRUE if end of () found */
+static long	brace_min[10];	/* Minimums for complex brace repeats */
+static long	brace_max[10];	/* Maximums for complex brace repeats */
+static int	brace_count[10]; /* Current counts for complex brace repeats */
+static int	one_exactly = FALSE;	/* only do one char for EXACTLY */
+
+/* When making changes to classchars also change nfa_classcodes. */
+static char_u	*classchars = (char_u *)".iIkKfFpPsSdDxXoOwWhHaAlLuU";
+static int	classcodes[] = {
+    ANY, IDENT, SIDENT, KWORD, SKWORD,
+    FNAME, SFNAME, PRINT, SPRINT,
+    WHITE, NWHITE, DIGIT, NDIGIT,
+    HEX, NHEX, OCTAL, NOCTAL,
+    WORD, NWORD, HEAD, NHEAD,
+    ALPHA, NALPHA, LOWER, NLOWER,
+    UPPER, NUPPER
+};
+
+/*
+ * When regcode is set to this value, code is not emitted and size is computed
+ * instead.
+ */
+#define JUST_CALC_SIZE	((char_u *) -1)
+
+/* Values for rs_state in regitem_T. */
+typedef enum regstate_E
+{
+    RS_NOPEN = 0	/* NOPEN and NCLOSE */
+    , RS_MOPEN		/* MOPEN + [0-9] */
+    , RS_MCLOSE		/* MCLOSE + [0-9] */
+#ifdef FEAT_SYN_HL
+    , RS_ZOPEN		/* ZOPEN + [0-9] */
+    , RS_ZCLOSE		/* ZCLOSE + [0-9] */
+#endif
+    , RS_BRANCH		/* BRANCH */
+    , RS_BRCPLX_MORE	/* BRACE_COMPLEX and trying one more match */
+    , RS_BRCPLX_LONG	/* BRACE_COMPLEX and trying longest match */
+    , RS_BRCPLX_SHORT	/* BRACE_COMPLEX and trying shortest match */
+    , RS_NOMATCH	/* NOMATCH */
+    , RS_BEHIND1	/* BEHIND / NOBEHIND matching rest */
+    , RS_BEHIND2	/* BEHIND / NOBEHIND matching behind part */
+    , RS_STAR_LONG	/* STAR/PLUS/BRACE_SIMPLE longest match */
+    , RS_STAR_SHORT	/* STAR/PLUS/BRACE_SIMPLE shortest match */
+} regstate_T;
+
+/*
+ * Structure used to save the current input state, when it needs to be
+ * restored after trying a match.  Used by reg_save() and reg_restore().
+ * Also stores the length of "backpos".
+ */
+typedef struct
+{
+    union
+    {
+	char_u	*ptr;	/* rex.input pointer, for single-line regexp */
+	lpos_T	pos;	/* rex.input pos, for multi-line regexp */
+    } rs_u;
+    int		rs_len;
+} regsave_T;
+
+/* struct to save start/end pointer/position in for \(\) */
+typedef struct
+{
+    union
+    {
+	char_u	*ptr;
+	lpos_T	pos;
+    } se_u;
+} save_se_T;
+
+/* used for BEHIND and NOBEHIND matching */
+typedef struct regbehind_S
+{
+    regsave_T	save_after;
+    regsave_T	save_behind;
+    int		save_need_clear_subexpr;
+    save_se_T   save_start[NSUBEXP];
+    save_se_T   save_end[NSUBEXP];
+} regbehind_T;
+
+/*
+ * When there are alternatives a regstate_T is put on the regstack to remember
+ * what we are doing.
+ * Before it may be another type of item, depending on rs_state, to remember
+ * more things.
+ */
+typedef struct regitem_S
+{
+    regstate_T	rs_state;	// what we are doing, one of RS_ above
+    short	rs_no;		// submatch nr or BEHIND/NOBEHIND
+    char_u	*rs_scan;	// current node in program
+    union
+    {
+	save_se_T  sesave;
+	regsave_T  regsave;
+    } rs_un;			// room for saving rex.input
+} regitem_T;
+
+
+/* used for STAR, PLUS and BRACE_SIMPLE matching */
+typedef struct regstar_S
+{
+    int		nextb;		/* next byte */
+    int		nextb_ic;	/* next byte reverse case */
+    long	count;
+    long	minval;
+    long	maxval;
+} regstar_T;
+
+/* used to store input position when a BACK was encountered, so that we now if
+ * we made any progress since the last time. */
+typedef struct backpos_S
+{
+    char_u	*bp_scan;	/* "scan" where BACK was encountered */
+    regsave_T	bp_pos;		/* last input position */
+} backpos_T;
+
+/*
+ * "regstack" and "backpos" are used by regmatch().  They are kept over calls
+ * to avoid invoking malloc() and free() often.
+ * "regstack" is a stack with regitem_T items, sometimes preceded by regstar_T
+ * or regbehind_T.
+ * "backpos_T" is a table with backpos_T for BACK
+ */
+static garray_T	regstack = {0, 0, 0, 0, NULL};
+static garray_T	backpos = {0, 0, 0, 0, NULL};
+
+static regsave_T behind_pos;
+
+/*
+ * Both for regstack and backpos tables we use the following strategy of
+ * allocation (to reduce malloc/free calls):
+ * - Initial size is fairly small.
+ * - When needed, the tables are grown bigger (8 times at first, double after
+ *   that).
+ * - After executing the match we free the memory only if the array has grown.
+ *   Thus the memory is kept allocated when it's at the initial size.
+ * This makes it fast while not keeping a lot of memory allocated.
+ * A three times speed increase was observed when using many simple patterns.
+ */
+#define REGSTACK_INITIAL	2048
+#define BACKPOS_INITIAL		64
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH	The set of branches constituting a single choice are hooked
+ *		together with their "next" pointers, since precedence prevents
+ *		anything being concatenated to any individual branch.  The
+ *		"next" pointer of the last BRANCH in a choice points to the
+ *		thing following the whole choice.  This is also where the
+ *		final "next" pointer of each individual branch points; each
+ *		branch starts with the operand node of a BRANCH node.
+ *
+ * BACK		Normal "next" pointers all implicitly point forward; BACK
+ *		exists to make loop structures possible.
+ *
+ * STAR,PLUS	'=', and complex '*' and '+', are implemented as circular
+ *		BRANCH structures using BACK.  Simple cases (one character
+ *		per match) are implemented with STAR and PLUS for speed
+ *		and to minimize recursive plunges.
+ *
+ * BRACE_LIMITS	This is always followed by a BRACE_SIMPLE or BRACE_COMPLEX
+ *		node, and defines the min and max limits to be used for that
+ *		node.
+ *
+ * MOPEN,MCLOSE	...are numbered at compile time.
+ * ZOPEN,ZCLOSE	...ditto
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit bytes, high order first.  The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node.  (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define OP(p)		((int)*(p))
+#define NEXT(p)		(((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377))
+#define OPERAND(p)	((p) + 3)
+/* Obtain an operand that was stored as four bytes, MSB first. */
+#define OPERAND_MIN(p)	(((long)(p)[3] << 24) + ((long)(p)[4] << 16) \
+			+ ((long)(p)[5] << 8) + (long)(p)[6])
+/* Obtain a second operand stored as four bytes. */
+#define OPERAND_MAX(p)	OPERAND_MIN((p) + 4)
+/* Obtain a second single-byte operand stored after a four bytes operand. */
+#define OPERAND_CMP(p)	(p)[7]
+
+static char_u *reg(int paren, int *flagp);
+
+#ifdef BT_REGEXP_DUMP
+static void	regdump(char_u *, bt_regprog_T *);
+#endif
+
+static int	re_num_cmp(long_u val, char_u *scan);
+
+#ifdef DEBUG
+static char_u	*regprop(char_u *);
+
+static int	regnarrate = 0;
+#endif
+
+
+/*
+ * Setup to parse the regexp.  Used once to get the length and once to do it.
+ */
+    static void
+regcomp_start(
+    char_u	*expr,
+    int		re_flags)	    /* see vim_regcomp() */
+{
+    initchr(expr);
+    if (re_flags & RE_MAGIC)
+	reg_magic = MAGIC_ON;
+    else
+	reg_magic = MAGIC_OFF;
+    reg_string = (re_flags & RE_STRING);
+    reg_strict = (re_flags & RE_STRICT);
+    get_cpo_flags();
+
+    num_complex_braces = 0;
+    regnpar = 1;
+    vim_memset(had_endbrace, 0, sizeof(had_endbrace));
+#ifdef FEAT_SYN_HL
+    regnzpar = 1;
+    re_has_z = 0;
+#endif
+    regsize = 0L;
+    reg_toolong = FALSE;
+    regflags = 0;
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+    had_eol = FALSE;
+#endif
+}
+
+/*
+ * Return TRUE if MULTIBYTECODE should be used instead of EXACTLY for
+ * character "c".
+ */
+    static int
+use_multibytecode(int c)
+{
+    return has_mbyte && (*mb_char2len)(c) > 1
+		     && (re_multi_type(peekchr()) != NOT_MULTI
+			     || (enc_utf8 && utf_iscomposing(c)));
+}
+
+/*
+ * Emit (if appropriate) a byte of code
+ */
+    static void
+regc(int b)
+{
+    if (regcode == JUST_CALC_SIZE)
+	regsize++;
+    else
+	*regcode++ = b;
+}
+
+/*
+ * Emit (if appropriate) a multi-byte character of code
+ */
+    static void
+regmbc(int c)
+{
+    if (!has_mbyte && c > 0xff)
+	return;
+    if (regcode == JUST_CALC_SIZE)
+	regsize += (*mb_char2len)(c);
+    else
+	regcode += (*mb_char2bytes)(c, regcode);
+}
+
+#define REGMBC(x) regmbc(x);
+#define CASEMBC(x) case x:
+
+/*
+ * Produce the bytes for equivalence class "c".
+ * Currently only handles latin1, latin9 and utf-8.
+ * NOTE: When changing this function, also change nfa_emit_equi_class()
+ */
+    static void
+reg_equi_class(int c)
+{
+    if (enc_utf8 || STRCMP(p_enc, "latin1") == 0
+					 || STRCMP(p_enc, "iso-8859-15") == 0)
+    {
+#ifdef EBCDIC
+	int i;
+
+	/* This might be slower than switch/case below. */
+	for (i = 0; i < 16; i++)
+	{
+	    if (vim_strchr(EQUIVAL_CLASS_C[i], c) != NULL)
+	    {
+		char *p = EQUIVAL_CLASS_C[i];
+
+		while (*p != 0)
+		    regmbc(*p++);
+		return;
+	    }
+	}
+#else
+	switch (c)
+	{
+	    /* Do not use '\300' style, it results in a negative number. */
+	    case 'A': case 0xc0: case 0xc1: case 0xc2:
+	    case 0xc3: case 0xc4: case 0xc5:
+	    CASEMBC(0x100) CASEMBC(0x102) CASEMBC(0x104) CASEMBC(0x1cd)
+	    CASEMBC(0x1de) CASEMBC(0x1e0) CASEMBC(0x1ea2)
+		      regmbc('A'); regmbc(0xc0); regmbc(0xc1);
+		      regmbc(0xc2); regmbc(0xc3); regmbc(0xc4);
+		      regmbc(0xc5);
+		      REGMBC(0x100) REGMBC(0x102) REGMBC(0x104)
+		      REGMBC(0x1cd) REGMBC(0x1de) REGMBC(0x1e0)
+		      REGMBC(0x1ea2)
+		      return;
+	    case 'B': CASEMBC(0x1e02) CASEMBC(0x1e06)
+		      regmbc('B'); REGMBC(0x1e02) REGMBC(0x1e06)
+		      return;
+	    case 'C': case 0xc7:
+	    CASEMBC(0x106) CASEMBC(0x108) CASEMBC(0x10a) CASEMBC(0x10c)
+		      regmbc('C'); regmbc(0xc7);
+		      REGMBC(0x106) REGMBC(0x108) REGMBC(0x10a)
+		      REGMBC(0x10c)
+		      return;
+	    case 'D': CASEMBC(0x10e) CASEMBC(0x110) CASEMBC(0x1e0a)
+	    CASEMBC(0x1e0e) CASEMBC(0x1e10)
+		      regmbc('D'); REGMBC(0x10e) REGMBC(0x110)
+		      REGMBC(0x1e0a) REGMBC(0x1e0e) REGMBC(0x1e10)
+		      return;
+	    case 'E': case 0xc8: case 0xc9: case 0xca: case 0xcb:
+	    CASEMBC(0x112) CASEMBC(0x114) CASEMBC(0x116) CASEMBC(0x118)
+	    CASEMBC(0x11a) CASEMBC(0x1eba) CASEMBC(0x1ebc)
+		      regmbc('E'); regmbc(0xc8); regmbc(0xc9);
+		      regmbc(0xca); regmbc(0xcb);
+		      REGMBC(0x112) REGMBC(0x114) REGMBC(0x116)
+		      REGMBC(0x118) REGMBC(0x11a) REGMBC(0x1eba)
+		      REGMBC(0x1ebc)
+		      return;
+	    case 'F': CASEMBC(0x1e1e)
+		      regmbc('F'); REGMBC(0x1e1e)
+		      return;
+	    case 'G': CASEMBC(0x11c) CASEMBC(0x11e) CASEMBC(0x120)
+	    CASEMBC(0x122) CASEMBC(0x1e4) CASEMBC(0x1e6) CASEMBC(0x1f4)
+	    CASEMBC(0x1e20)
+		      regmbc('G'); REGMBC(0x11c) REGMBC(0x11e)
+		      REGMBC(0x120) REGMBC(0x122) REGMBC(0x1e4)
+		      REGMBC(0x1e6) REGMBC(0x1f4) REGMBC(0x1e20)
+		      return;
+	    case 'H': CASEMBC(0x124) CASEMBC(0x126) CASEMBC(0x1e22)
+	    CASEMBC(0x1e26) CASEMBC(0x1e28)
+		      regmbc('H'); REGMBC(0x124) REGMBC(0x126)
+		      REGMBC(0x1e22) REGMBC(0x1e26) REGMBC(0x1e28)
+		      return;
+	    case 'I': case 0xcc: case 0xcd: case 0xce: case 0xcf:
+	    CASEMBC(0x128) CASEMBC(0x12a) CASEMBC(0x12c) CASEMBC(0x12e)
+	    CASEMBC(0x130) CASEMBC(0x1cf) CASEMBC(0x1ec8)
+		      regmbc('I'); regmbc(0xcc); regmbc(0xcd);
+		      regmbc(0xce); regmbc(0xcf);
+		      REGMBC(0x128) REGMBC(0x12a) REGMBC(0x12c)
+		      REGMBC(0x12e) REGMBC(0x130) REGMBC(0x1cf)
+		      REGMBC(0x1ec8)
+		      return;
+	    case 'J': CASEMBC(0x134)
+		      regmbc('J'); REGMBC(0x134)
+		      return;
+	    case 'K': CASEMBC(0x136) CASEMBC(0x1e8) CASEMBC(0x1e30)
+	    CASEMBC(0x1e34)
+		      regmbc('K'); REGMBC(0x136) REGMBC(0x1e8)
+		      REGMBC(0x1e30) REGMBC(0x1e34)
+		      return;
+	    case 'L': CASEMBC(0x139) CASEMBC(0x13b) CASEMBC(0x13d)
+	    CASEMBC(0x13f) CASEMBC(0x141) CASEMBC(0x1e3a)
+		      regmbc('L'); REGMBC(0x139) REGMBC(0x13b)
+		      REGMBC(0x13d) REGMBC(0x13f) REGMBC(0x141)
+		      REGMBC(0x1e3a)
+		      return;
+	    case 'M': CASEMBC(0x1e3e) CASEMBC(0x1e40)
+		      regmbc('M'); REGMBC(0x1e3e) REGMBC(0x1e40)
+		      return;
+	    case 'N': case 0xd1:
+	    CASEMBC(0x143) CASEMBC(0x145) CASEMBC(0x147) CASEMBC(0x1e44)
+	    CASEMBC(0x1e48)
+		      regmbc('N'); regmbc(0xd1);
+		      REGMBC(0x143) REGMBC(0x145) REGMBC(0x147)
+		      REGMBC(0x1e44) REGMBC(0x1e48)
+		      return;
+	    case 'O': case 0xd2: case 0xd3: case 0xd4: case 0xd5:
+	    case 0xd6: case 0xd8:
+	    CASEMBC(0x14c) CASEMBC(0x14e) CASEMBC(0x150) CASEMBC(0x1a0)
+	    CASEMBC(0x1d1) CASEMBC(0x1ea) CASEMBC(0x1ec) CASEMBC(0x1ece)
+		      regmbc('O'); regmbc(0xd2); regmbc(0xd3);
+		      regmbc(0xd4); regmbc(0xd5); regmbc(0xd6);
+		      regmbc(0xd8);
+		      REGMBC(0x14c) REGMBC(0x14e) REGMBC(0x150)
+		      REGMBC(0x1a0) REGMBC(0x1d1) REGMBC(0x1ea)
+		      REGMBC(0x1ec) REGMBC(0x1ece)
+		      return;
+	    case 'P': case 0x1e54: case 0x1e56:
+		      regmbc('P'); REGMBC(0x1e54) REGMBC(0x1e56)
+		      return;
+	    case 'R': CASEMBC(0x154) CASEMBC(0x156) CASEMBC(0x158)
+	    CASEMBC(0x1e58) CASEMBC(0x1e5e)
+		      regmbc('R'); REGMBC(0x154) REGMBC(0x156) REGMBC(0x158)
+		      REGMBC(0x1e58) REGMBC(0x1e5e)
+		      return;
+	    case 'S': CASEMBC(0x15a) CASEMBC(0x15c) CASEMBC(0x15e)
+	    CASEMBC(0x160) CASEMBC(0x1e60)
+		      regmbc('S'); REGMBC(0x15a) REGMBC(0x15c)
+		      REGMBC(0x15e) REGMBC(0x160) REGMBC(0x1e60)
+		      return;
+	    case 'T': CASEMBC(0x162) CASEMBC(0x164) CASEMBC(0x166)
+	    CASEMBC(0x1e6a) CASEMBC(0x1e6e)
+		      regmbc('T'); REGMBC(0x162) REGMBC(0x164)
+		      REGMBC(0x166) REGMBC(0x1e6a) REGMBC(0x1e6e)
+		      return;
+	    case 'U': case 0xd9: case 0xda: case 0xdb: case 0xdc:
+	    CASEMBC(0x168) CASEMBC(0x16a) CASEMBC(0x16c) CASEMBC(0x16e)
+	    CASEMBC(0x170) CASEMBC(0x172) CASEMBC(0x1af) CASEMBC(0x1d3)
+	    CASEMBC(0x1ee6)
+		      regmbc('U'); regmbc(0xd9); regmbc(0xda);
+		      regmbc(0xdb); regmbc(0xdc);
+		      REGMBC(0x168) REGMBC(0x16a) REGMBC(0x16c)
+		      REGMBC(0x16e) REGMBC(0x170) REGMBC(0x172)
+		      REGMBC(0x1af) REGMBC(0x1d3) REGMBC(0x1ee6)
+		      return;
+	    case 'V': CASEMBC(0x1e7c)
+		      regmbc('V'); REGMBC(0x1e7c)
+		      return;
+	    case 'W': CASEMBC(0x174) CASEMBC(0x1e80) CASEMBC(0x1e82)
+	    CASEMBC(0x1e84) CASEMBC(0x1e86)
+		      regmbc('W'); REGMBC(0x174) REGMBC(0x1e80)
+		      REGMBC(0x1e82) REGMBC(0x1e84) REGMBC(0x1e86)
+		      return;
+	    case 'X': CASEMBC(0x1e8a) CASEMBC(0x1e8c)
+		      regmbc('X'); REGMBC(0x1e8a) REGMBC(0x1e8c)
+		      return;
+	    case 'Y': case 0xdd:
+	    CASEMBC(0x176) CASEMBC(0x178) CASEMBC(0x1e8e) CASEMBC(0x1ef2)
+	    CASEMBC(0x1ef6) CASEMBC(0x1ef8)
+		      regmbc('Y'); regmbc(0xdd);
+		      REGMBC(0x176) REGMBC(0x178) REGMBC(0x1e8e)
+		      REGMBC(0x1ef2) REGMBC(0x1ef6) REGMBC(0x1ef8)
+		      return;
+	    case 'Z': CASEMBC(0x179) CASEMBC(0x17b) CASEMBC(0x17d)
+	    CASEMBC(0x1b5) CASEMBC(0x1e90) CASEMBC(0x1e94)
+		      regmbc('Z'); REGMBC(0x179) REGMBC(0x17b)
+		      REGMBC(0x17d) REGMBC(0x1b5) REGMBC(0x1e90)
+		      REGMBC(0x1e94)
+		      return;
+	    case 'a': case 0xe0: case 0xe1: case 0xe2:
+	    case 0xe3: case 0xe4: case 0xe5:
+	    CASEMBC(0x101) CASEMBC(0x103) CASEMBC(0x105) CASEMBC(0x1ce)
+	    CASEMBC(0x1df) CASEMBC(0x1e1) CASEMBC(0x1ea3)
+		      regmbc('a'); regmbc(0xe0); regmbc(0xe1);
+		      regmbc(0xe2); regmbc(0xe3); regmbc(0xe4);
+		      regmbc(0xe5);
+		      REGMBC(0x101) REGMBC(0x103) REGMBC(0x105)
+		      REGMBC(0x1ce) REGMBC(0x1df) REGMBC(0x1e1)
+		      REGMBC(0x1ea3)
+		      return;
+	    case 'b': CASEMBC(0x1e03) CASEMBC(0x1e07)
+		      regmbc('b'); REGMBC(0x1e03) REGMBC(0x1e07)
+		      return;
+	    case 'c': case 0xe7:
+	    CASEMBC(0x107) CASEMBC(0x109) CASEMBC(0x10b) CASEMBC(0x10d)
+		      regmbc('c'); regmbc(0xe7);
+		      REGMBC(0x107) REGMBC(0x109) REGMBC(0x10b)
+		      REGMBC(0x10d)
+		      return;
+	    case 'd': CASEMBC(0x10f) CASEMBC(0x111) CASEMBC(0x1e0b)
+	    CASEMBC(0x1e0f) CASEMBC(0x1e11)
+		      regmbc('d'); REGMBC(0x10f) REGMBC(0x111)
+		      REGMBC(0x1e0b) REGMBC(0x1e0f) REGMBC(0x1e11)
+		      return;
+	    case 'e': case 0xe8: case 0xe9: case 0xea: case 0xeb:
+	    CASEMBC(0x113) CASEMBC(0x115) CASEMBC(0x117) CASEMBC(0x119)
+	    CASEMBC(0x11b) CASEMBC(0x1ebb) CASEMBC(0x1ebd)
+		      regmbc('e'); regmbc(0xe8); regmbc(0xe9);
+		      regmbc(0xea); regmbc(0xeb);
+		      REGMBC(0x113) REGMBC(0x115) REGMBC(0x117)
+		      REGMBC(0x119) REGMBC(0x11b) REGMBC(0x1ebb)
+		      REGMBC(0x1ebd)
+		      return;
+	    case 'f': CASEMBC(0x1e1f)
+		      regmbc('f'); REGMBC(0x1e1f)
+		      return;
+	    case 'g': CASEMBC(0x11d) CASEMBC(0x11f) CASEMBC(0x121)
+	    CASEMBC(0x123) CASEMBC(0x1e5) CASEMBC(0x1e7) CASEMBC(0x1f5)
+	    CASEMBC(0x1e21)
+		      regmbc('g'); REGMBC(0x11d) REGMBC(0x11f)
+		      REGMBC(0x121) REGMBC(0x123) REGMBC(0x1e5)
+		      REGMBC(0x1e7) REGMBC(0x1f5) REGMBC(0x1e21)
+		      return;
+	    case 'h': CASEMBC(0x125) CASEMBC(0x127) CASEMBC(0x1e23)
+	    CASEMBC(0x1e27) CASEMBC(0x1e29) CASEMBC(0x1e96)
+		      regmbc('h'); REGMBC(0x125) REGMBC(0x127)
+		      REGMBC(0x1e23) REGMBC(0x1e27) REGMBC(0x1e29)
+		      REGMBC(0x1e96)
+		      return;
+	    case 'i': case 0xec: case 0xed: case 0xee: case 0xef:
+	    CASEMBC(0x129) CASEMBC(0x12b) CASEMBC(0x12d) CASEMBC(0x12f)
+	    CASEMBC(0x1d0) CASEMBC(0x1ec9)
+		      regmbc('i'); regmbc(0xec); regmbc(0xed);
+		      regmbc(0xee); regmbc(0xef);
+		      REGMBC(0x129) REGMBC(0x12b) REGMBC(0x12d)
+		      REGMBC(0x12f) REGMBC(0x1d0) REGMBC(0x1ec9)
+		      return;
+	    case 'j': CASEMBC(0x135) CASEMBC(0x1f0)
+		      regmbc('j'); REGMBC(0x135) REGMBC(0x1f0)
+		      return;
+	    case 'k': CASEMBC(0x137) CASEMBC(0x1e9) CASEMBC(0x1e31)
+	    CASEMBC(0x1e35)
+		      regmbc('k'); REGMBC(0x137) REGMBC(0x1e9)
+		      REGMBC(0x1e31) REGMBC(0x1e35)
+		      return;
+	    case 'l': CASEMBC(0x13a) CASEMBC(0x13c) CASEMBC(0x13e)
+	    CASEMBC(0x140) CASEMBC(0x142) CASEMBC(0x1e3b)
+		      regmbc('l'); REGMBC(0x13a) REGMBC(0x13c)
+		      REGMBC(0x13e) REGMBC(0x140) REGMBC(0x142)
+		      REGMBC(0x1e3b)
+		      return;
+	    case 'm': CASEMBC(0x1e3f) CASEMBC(0x1e41)
+		      regmbc('m'); REGMBC(0x1e3f) REGMBC(0x1e41)
+		      return;
+	    case 'n': case 0xf1:
+	    CASEMBC(0x144) CASEMBC(0x146) CASEMBC(0x148) CASEMBC(0x149)
+	    CASEMBC(0x1e45) CASEMBC(0x1e49)
+		      regmbc('n'); regmbc(0xf1);
+		      REGMBC(0x144) REGMBC(0x146) REGMBC(0x148)
+		      REGMBC(0x149) REGMBC(0x1e45) REGMBC(0x1e49)
+		      return;
+	    case 'o': case 0xf2: case 0xf3: case 0xf4: case 0xf5:
+	    case 0xf6: case 0xf8:
+	    CASEMBC(0x14d) CASEMBC(0x14f) CASEMBC(0x151) CASEMBC(0x1a1)
+	    CASEMBC(0x1d2) CASEMBC(0x1eb) CASEMBC(0x1ed) CASEMBC(0x1ecf)
+		      regmbc('o'); regmbc(0xf2); regmbc(0xf3);
+		      regmbc(0xf4); regmbc(0xf5); regmbc(0xf6);
+		      regmbc(0xf8);
+		      REGMBC(0x14d) REGMBC(0x14f) REGMBC(0x151)
+		      REGMBC(0x1a1) REGMBC(0x1d2) REGMBC(0x1eb)
+		      REGMBC(0x1ed) REGMBC(0x1ecf)
+		      return;
+	    case 'p': CASEMBC(0x1e55) CASEMBC(0x1e57)
+		      regmbc('p'); REGMBC(0x1e55) REGMBC(0x1e57)
+		      return;
+	    case 'r': CASEMBC(0x155) CASEMBC(0x157) CASEMBC(0x159)
+	    CASEMBC(0x1e59) CASEMBC(0x1e5f)
+		      regmbc('r'); REGMBC(0x155) REGMBC(0x157) REGMBC(0x159)
+		      REGMBC(0x1e59) REGMBC(0x1e5f)
+		      return;
+	    case 's': CASEMBC(0x15b) CASEMBC(0x15d) CASEMBC(0x15f)
+	    CASEMBC(0x161) CASEMBC(0x1e61)
+		      regmbc('s'); REGMBC(0x15b) REGMBC(0x15d)
+		      REGMBC(0x15f) REGMBC(0x161) REGMBC(0x1e61)
+		      return;
+	    case 't': CASEMBC(0x163) CASEMBC(0x165) CASEMBC(0x167)
+	    CASEMBC(0x1e6b) CASEMBC(0x1e6f) CASEMBC(0x1e97)
+		      regmbc('t'); REGMBC(0x163) REGMBC(0x165) REGMBC(0x167)
+		      REGMBC(0x1e6b) REGMBC(0x1e6f) REGMBC(0x1e97)
+		      return;
+	    case 'u': case 0xf9: case 0xfa: case 0xfb: case 0xfc:
+	    CASEMBC(0x169) CASEMBC(0x16b) CASEMBC(0x16d) CASEMBC(0x16f)
+	    CASEMBC(0x171) CASEMBC(0x173) CASEMBC(0x1b0) CASEMBC(0x1d4)
+	    CASEMBC(0x1ee7)
+		      regmbc('u'); regmbc(0xf9); regmbc(0xfa);
+		      regmbc(0xfb); regmbc(0xfc);
+		      REGMBC(0x169) REGMBC(0x16b) REGMBC(0x16d)
+		      REGMBC(0x16f) REGMBC(0x171) REGMBC(0x173)
+		      REGMBC(0x1b0) REGMBC(0x1d4) REGMBC(0x1ee7)
+		      return;
+	    case 'v': CASEMBC(0x1e7d)
+		      regmbc('v'); REGMBC(0x1e7d)
+		      return;
+	    case 'w': CASEMBC(0x175) CASEMBC(0x1e81) CASEMBC(0x1e83)
+	    CASEMBC(0x1e85) CASEMBC(0x1e87) CASEMBC(0x1e98)
+		      regmbc('w'); REGMBC(0x175) REGMBC(0x1e81)
+		      REGMBC(0x1e83) REGMBC(0x1e85) REGMBC(0x1e87)
+		      REGMBC(0x1e98)
+		      return;
+	    case 'x': CASEMBC(0x1e8b) CASEMBC(0x1e8d)
+		      regmbc('x'); REGMBC(0x1e8b) REGMBC(0x1e8d)
+		      return;
+	    case 'y': case 0xfd: case 0xff:
+	    CASEMBC(0x177) CASEMBC(0x1e8f) CASEMBC(0x1e99)
+	    CASEMBC(0x1ef3) CASEMBC(0x1ef7) CASEMBC(0x1ef9)
+		      regmbc('y'); regmbc(0xfd); regmbc(0xff);
+		      REGMBC(0x177) REGMBC(0x1e8f) REGMBC(0x1e99)
+		      REGMBC(0x1ef3) REGMBC(0x1ef7) REGMBC(0x1ef9)
+		      return;
+	    case 'z': CASEMBC(0x17a) CASEMBC(0x17c) CASEMBC(0x17e)
+	    CASEMBC(0x1b6) CASEMBC(0x1e91) CASEMBC(0x1e95)
+		      regmbc('z'); REGMBC(0x17a) REGMBC(0x17c)
+		      REGMBC(0x17e) REGMBC(0x1b6) REGMBC(0x1e91)
+		      REGMBC(0x1e95)
+		      return;
+	}
+#endif
+    }
+    regmbc(c);
+}
+
+/*
+ * Emit a node.
+ * Return pointer to generated code.
+ */
+    static char_u *
+regnode(int op)
+{
+    char_u  *ret;
+
+    ret = regcode;
+    if (ret == JUST_CALC_SIZE)
+	regsize += 3;
+    else
+    {
+	*regcode++ = op;
+	*regcode++ = NUL;		/* Null "next" pointer. */
+	*regcode++ = NUL;
+    }
+    return ret;
+}
+
+/*
+ * Write a long as four bytes at "p" and return pointer to the next char.
+ */
+    static char_u *
+re_put_long(char_u *p, long_u val)
+{
+    *p++ = (char_u) ((val >> 24) & 0377);
+    *p++ = (char_u) ((val >> 16) & 0377);
+    *p++ = (char_u) ((val >> 8) & 0377);
+    *p++ = (char_u) (val & 0377);
+    return p;
+}
+
+/*
+ * regnext - dig the "next" pointer out of a node
+ * Returns NULL when calculating size, when there is no next item and when
+ * there is an error.
+ */
+    static char_u *
+regnext(char_u *p)
+{
+    int	    offset;
+
+    if (p == JUST_CALC_SIZE || reg_toolong)
+	return NULL;
+
+    offset = NEXT(p);
+    if (offset == 0)
+	return NULL;
+
+    if (OP(p) == BACK)
+	return p - offset;
+    else
+	return p + offset;
+}
+
+/*
+ * Set the next-pointer at the end of a node chain.
+ */
+    static void
+regtail(char_u *p, char_u *val)
+{
+    char_u	*scan;
+    char_u	*temp;
+    int		offset;
+
+    if (p == JUST_CALC_SIZE)
+	return;
+
+    /* Find last node. */
+    scan = p;
+    for (;;)
+    {
+	temp = regnext(scan);
+	if (temp == NULL)
+	    break;
+	scan = temp;
+    }
+
+    if (OP(scan) == BACK)
+	offset = (int)(scan - val);
+    else
+	offset = (int)(val - scan);
+    /* When the offset uses more than 16 bits it can no longer fit in the two
+     * bytes available.  Use a global flag to avoid having to check return
+     * values in too many places. */
+    if (offset > 0xffff)
+	reg_toolong = TRUE;
+    else
+    {
+	*(scan + 1) = (char_u) (((unsigned)offset >> 8) & 0377);
+	*(scan + 2) = (char_u) (offset & 0377);
+    }
+}
+
+/*
+ * Like regtail, on item after a BRANCH; nop if none.
+ */
+    static void
+regoptail(char_u *p, char_u *val)
+{
+    /* When op is neither BRANCH nor BRACE_COMPLEX0-9, it is "operandless" */
+    if (p == NULL || p == JUST_CALC_SIZE
+	    || (OP(p) != BRANCH
+		&& (OP(p) < BRACE_COMPLEX || OP(p) > BRACE_COMPLEX + 9)))
+	return;
+    regtail(OPERAND(p), val);
+}
+
+/*
+ * Insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+    static void
+reginsert(int op, char_u *opnd)
+{
+    char_u	*src;
+    char_u	*dst;
+    char_u	*place;
+
+    if (regcode == JUST_CALC_SIZE)
+    {
+	regsize += 3;
+	return;
+    }
+    src = regcode;
+    regcode += 3;
+    dst = regcode;
+    while (src > opnd)
+	*--dst = *--src;
+
+    place = opnd;		/* Op node, where operand used to be. */
+    *place++ = op;
+    *place++ = NUL;
+    *place = NUL;
+}
+
+/*
+ * Insert an operator in front of already-emitted operand.
+ * Add a number to the operator.
+ */
+    static void
+reginsert_nr(int op, long val, char_u *opnd)
+{
+    char_u	*src;
+    char_u	*dst;
+    char_u	*place;
+
+    if (regcode == JUST_CALC_SIZE)
+    {
+	regsize += 7;
+	return;
+    }
+    src = regcode;
+    regcode += 7;
+    dst = regcode;
+    while (src > opnd)
+	*--dst = *--src;
+
+    place = opnd;		/* Op node, where operand used to be. */
+    *place++ = op;
+    *place++ = NUL;
+    *place++ = NUL;
+    re_put_long(place, (long_u)val);
+}
+
+/*
+ * Insert an operator in front of already-emitted operand.
+ * The operator has the given limit values as operands.  Also set next pointer.
+ *
+ * Means relocating the operand.
+ */
+    static void
+reginsert_limits(
+    int		op,
+    long	minval,
+    long	maxval,
+    char_u	*opnd)
+{
+    char_u	*src;
+    char_u	*dst;
+    char_u	*place;
+
+    if (regcode == JUST_CALC_SIZE)
+    {
+	regsize += 11;
+	return;
+    }
+    src = regcode;
+    regcode += 11;
+    dst = regcode;
+    while (src > opnd)
+	*--dst = *--src;
+
+    place = opnd;		/* Op node, where operand used to be. */
+    *place++ = op;
+    *place++ = NUL;
+    *place++ = NUL;
+    place = re_put_long(place, (long_u)minval);
+    place = re_put_long(place, (long_u)maxval);
+    regtail(opnd, place);
+}
+
+/*
+ * Return TRUE if the back reference is legal. We must have seen the close
+ * brace.
+ * TODO: Should also check that we don't refer to something that is repeated
+ * (+*=): what instance of the repetition should we match?
+ */
+    static int
+seen_endbrace(int refnum)
+{
+    if (!had_endbrace[refnum])
+    {
+	char_u *p;
+
+	/* Trick: check if "@<=" or "@<!" follows, in which case
+	 * the \1 can appear before the referenced match. */
+	for (p = regparse; *p != NUL; ++p)
+	    if (p[0] == '@' && p[1] == '<' && (p[2] == '!' || p[2] == '='))
+		break;
+	if (*p == NUL)
+	{
+	    emsg(_("E65: Illegal back reference"));
+	    rc_did_emsg = TRUE;
+	    return FALSE;
+	}
+    }
+    return TRUE;
+}
+
+/*
+ * Parse the lowest level.
+ *
+ * Optimization:  gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run.  Don't do this when one_exactly is set.
+ */
+    static char_u *
+regatom(int *flagp)
+{
+    char_u	    *ret;
+    int		    flags;
+    int		    c;
+    char_u	    *p;
+    int		    extra = 0;
+    int		    save_prev_at_start = prev_at_start;
+
+    *flagp = WORST;		/* Tentatively. */
+
+    c = getchr();
+    switch (c)
+    {
+      case Magic('^'):
+	ret = regnode(BOL);
+	break;
+
+      case Magic('$'):
+	ret = regnode(EOL);
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+	had_eol = TRUE;
+#endif
+	break;
+
+      case Magic('<'):
+	ret = regnode(BOW);
+	break;
+
+      case Magic('>'):
+	ret = regnode(EOW);
+	break;
+
+      case Magic('_'):
+	c = no_Magic(getchr());
+	if (c == '^')		/* "\_^" is start-of-line */
+	{
+	    ret = regnode(BOL);
+	    break;
+	}
+	if (c == '$')		/* "\_$" is end-of-line */
+	{
+	    ret = regnode(EOL);
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+	    had_eol = TRUE;
+#endif
+	    break;
+	}
+
+	extra = ADD_NL;
+	*flagp |= HASNL;
+
+	/* "\_[" is character range plus newline */
+	if (c == '[')
+	    goto collection;
+
+	/* "\_x" is character class plus newline */
+	/* FALLTHROUGH */
+
+	/*
+	 * Character classes.
+	 */
+      case Magic('.'):
+      case Magic('i'):
+      case Magic('I'):
+      case Magic('k'):
+      case Magic('K'):
+      case Magic('f'):
+      case Magic('F'):
+      case Magic('p'):
+      case Magic('P'):
+      case Magic('s'):
+      case Magic('S'):
+      case Magic('d'):
+      case Magic('D'):
+      case Magic('x'):
+      case Magic('X'):
+      case Magic('o'):
+      case Magic('O'):
+      case Magic('w'):
+      case Magic('W'):
+      case Magic('h'):
+      case Magic('H'):
+      case Magic('a'):
+      case Magic('A'):
+      case Magic('l'):
+      case Magic('L'):
+      case Magic('u'):
+      case Magic('U'):
+	p = vim_strchr(classchars, no_Magic(c));
+	if (p == NULL)
+	    EMSG_RET_NULL(_("E63: invalid use of \\_"));
+
+	/* When '.' is followed by a composing char ignore the dot, so that
+	 * the composing char is matched here. */
+	if (enc_utf8 && c == Magic('.') && utf_iscomposing(peekchr()))
+	{
+	    c = getchr();
+	    goto do_multibyte;
+	}
+	ret = regnode(classcodes[p - classchars] + extra);
+	*flagp |= HASWIDTH | SIMPLE;
+	break;
+
+      case Magic('n'):
+	if (reg_string)
+	{
+	    /* In a string "\n" matches a newline character. */
+	    ret = regnode(EXACTLY);
+	    regc(NL);
+	    regc(NUL);
+	    *flagp |= HASWIDTH | SIMPLE;
+	}
+	else
+	{
+	    /* In buffer text "\n" matches the end of a line. */
+	    ret = regnode(NEWL);
+	    *flagp |= HASWIDTH | HASNL;
+	}
+	break;
+
+      case Magic('('):
+	if (one_exactly)
+	    EMSG_ONE_RET_NULL;
+	ret = reg(REG_PAREN, &flags);
+	if (ret == NULL)
+	    return NULL;
+	*flagp |= flags & (HASWIDTH | SPSTART | HASNL | HASLOOKBH);
+	break;
+
+      case NUL:
+      case Magic('|'):
+      case Magic('&'):
+      case Magic(')'):
+	if (one_exactly)
+	    EMSG_ONE_RET_NULL;
+	IEMSG_RET_NULL(_(e_internal));	/* Supposed to be caught earlier. */
+	/* NOTREACHED */
+
+      case Magic('='):
+      case Magic('?'):
+      case Magic('+'):
+      case Magic('@'):
+      case Magic('{'):
+      case Magic('*'):
+	c = no_Magic(c);
+	EMSG3_RET_NULL(_("E64: %s%c follows nothing"),
+		(c == '*' ? reg_magic >= MAGIC_ON : reg_magic == MAGIC_ALL), c);
+	/* NOTREACHED */
+
+      case Magic('~'):		/* previous substitute pattern */
+	    if (reg_prev_sub != NULL)
+	    {
+		char_u	    *lp;
+
+		ret = regnode(EXACTLY);
+		lp = reg_prev_sub;
+		while (*lp != NUL)
+		    regc(*lp++);
+		regc(NUL);
+		if (*reg_prev_sub != NUL)
+		{
+		    *flagp |= HASWIDTH;
+		    if ((lp - reg_prev_sub) == 1)
+			*flagp |= SIMPLE;
+		}
+	    }
+	    else
+		EMSG_RET_NULL(_(e_nopresub));
+	    break;
+
+      case Magic('1'):
+      case Magic('2'):
+      case Magic('3'):
+      case Magic('4'):
+      case Magic('5'):
+      case Magic('6'):
+      case Magic('7'):
+      case Magic('8'):
+      case Magic('9'):
+	    {
+		int		    refnum;
+
+		refnum = c - Magic('0');
+		if (!seen_endbrace(refnum))
+		    return NULL;
+		ret = regnode(BACKREF + refnum);
+	    }
+	    break;
+
+      case Magic('z'):
+	{
+	    c = no_Magic(getchr());
+	    switch (c)
+	    {
+#ifdef FEAT_SYN_HL
+		case '(': if ((reg_do_extmatch & REX_SET) == 0)
+			      EMSG_RET_NULL(_(e_z_not_allowed));
+			  if (one_exactly)
+			      EMSG_ONE_RET_NULL;
+			  ret = reg(REG_ZPAREN, &flags);
+			  if (ret == NULL)
+			      return NULL;
+			  *flagp |= flags & (HASWIDTH|SPSTART|HASNL|HASLOOKBH);
+			  re_has_z = REX_SET;
+			  break;
+
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9': if ((reg_do_extmatch & REX_USE) == 0)
+			      EMSG_RET_NULL(_(e_z1_not_allowed));
+			  ret = regnode(ZREF + c - '0');
+			  re_has_z = REX_USE;
+			  break;
+#endif
+
+		case 's': ret = regnode(MOPEN + 0);
+			  if (re_mult_next("\\zs") == FAIL)
+			      return NULL;
+			  break;
+
+		case 'e': ret = regnode(MCLOSE + 0);
+			  if (re_mult_next("\\ze") == FAIL)
+			      return NULL;
+			  break;
+
+		default:  EMSG_RET_NULL(_("E68: Invalid character after \\z"));
+	    }
+	}
+	break;
+
+      case Magic('%'):
+	{
+	    c = no_Magic(getchr());
+	    switch (c)
+	    {
+		/* () without a back reference */
+		case '(':
+		    if (one_exactly)
+			EMSG_ONE_RET_NULL;
+		    ret = reg(REG_NPAREN, &flags);
+		    if (ret == NULL)
+			return NULL;
+		    *flagp |= flags & (HASWIDTH | SPSTART | HASNL | HASLOOKBH);
+		    break;
+
+		/* Catch \%^ and \%$ regardless of where they appear in the
+		 * pattern -- regardless of whether or not it makes sense. */
+		case '^':
+		    ret = regnode(RE_BOF);
+		    break;
+
+		case '$':
+		    ret = regnode(RE_EOF);
+		    break;
+
+		case '#':
+		    ret = regnode(CURSOR);
+		    break;
+
+		case 'V':
+		    ret = regnode(RE_VISUAL);
+		    break;
+
+		case 'C':
+		    ret = regnode(RE_COMPOSING);
+		    break;
+
+		/* \%[abc]: Emit as a list of branches, all ending at the last
+		 * branch which matches nothing. */
+		case '[':
+			  if (one_exactly)	/* doesn't nest */
+			      EMSG_ONE_RET_NULL;
+			  {
+			      char_u	*lastbranch;
+			      char_u	*lastnode = NULL;
+			      char_u	*br;
+
+			      ret = NULL;
+			      while ((c = getchr()) != ']')
+			      {
+				  if (c == NUL)
+				      EMSG2_RET_NULL(_(e_missing_sb),
+						      reg_magic == MAGIC_ALL);
+				  br = regnode(BRANCH);
+				  if (ret == NULL)
+				      ret = br;
+				  else
+				  {
+				      regtail(lastnode, br);
+				      if (reg_toolong)
+					  return NULL;
+				  }
+
+				  ungetchr();
+				  one_exactly = TRUE;
+				  lastnode = regatom(flagp);
+				  one_exactly = FALSE;
+				  if (lastnode == NULL)
+				      return NULL;
+			      }
+			      if (ret == NULL)
+				  EMSG2_RET_NULL(_(e_empty_sb),
+						      reg_magic == MAGIC_ALL);
+			      lastbranch = regnode(BRANCH);
+			      br = regnode(NOTHING);
+			      if (ret != JUST_CALC_SIZE)
+			      {
+				  regtail(lastnode, br);
+				  regtail(lastbranch, br);
+				  /* connect all branches to the NOTHING
+				   * branch at the end */
+				  for (br = ret; br != lastnode; )
+				  {
+				      if (OP(br) == BRANCH)
+				      {
+					  regtail(br, lastbranch);
+					  if (reg_toolong)
+					      return NULL;
+					  br = OPERAND(br);
+				      }
+				      else
+					  br = regnext(br);
+				  }
+			      }
+			      *flagp &= ~(HASWIDTH | SIMPLE);
+			      break;
+			  }
+
+		case 'd':   /* %d123 decimal */
+		case 'o':   /* %o123 octal */
+		case 'x':   /* %xab hex 2 */
+		case 'u':   /* %uabcd hex 4 */
+		case 'U':   /* %U1234abcd hex 8 */
+			  {
+			      long i;
+
+			      switch (c)
+			      {
+				  case 'd': i = getdecchrs(); break;
+				  case 'o': i = getoctchrs(); break;
+				  case 'x': i = gethexchrs(2); break;
+				  case 'u': i = gethexchrs(4); break;
+				  case 'U': i = gethexchrs(8); break;
+				  default:  i = -1; break;
+			      }
+
+			      if (i < 0 || i > INT_MAX)
+				  EMSG2_RET_NULL(
+					_("E678: Invalid character after %s%%[dxouU]"),
+					reg_magic == MAGIC_ALL);
+			      if (use_multibytecode(i))
+				  ret = regnode(MULTIBYTECODE);
+			      else
+				  ret = regnode(EXACTLY);
+			      if (i == 0)
+				  regc(0x0a);
+			      else
+				  regmbc(i);
+			      regc(NUL);
+			      *flagp |= HASWIDTH;
+			      break;
+			  }
+
+		default:
+			  if (VIM_ISDIGIT(c) || c == '<' || c == '>'
+								 || c == '\'')
+			  {
+			      long_u	n = 0;
+			      int	cmp;
+
+			      cmp = c;
+			      if (cmp == '<' || cmp == '>')
+				  c = getchr();
+			      while (VIM_ISDIGIT(c))
+			      {
+				  n = n * 10 + (c - '0');
+				  c = getchr();
+			      }
+			      if (c == '\'' && n == 0)
+			      {
+				  /* "\%'m", "\%<'m" and "\%>'m": Mark */
+				  c = getchr();
+				  ret = regnode(RE_MARK);
+				  if (ret == JUST_CALC_SIZE)
+				      regsize += 2;
+				  else
+				  {
+				      *regcode++ = c;
+				      *regcode++ = cmp;
+				  }
+				  break;
+			      }
+			      else if (c == 'l' || c == 'c' || c == 'v')
+			      {
+				  if (c == 'l')
+				  {
+				      ret = regnode(RE_LNUM);
+				      if (save_prev_at_start)
+					  at_start = TRUE;
+				  }
+				  else if (c == 'c')
+				      ret = regnode(RE_COL);
+				  else
+				      ret = regnode(RE_VCOL);
+				  if (ret == JUST_CALC_SIZE)
+				      regsize += 5;
+				  else
+				  {
+				      /* put the number and the optional
+				       * comparator after the opcode */
+				      regcode = re_put_long(regcode, n);
+				      *regcode++ = cmp;
+				  }
+				  break;
+			      }
+			  }
+
+			  EMSG2_RET_NULL(_("E71: Invalid character after %s%%"),
+						      reg_magic == MAGIC_ALL);
+	    }
+	}
+	break;
+
+      case Magic('['):
+collection:
+	{
+	    char_u	*lp;
+
+	    /*
+	     * If there is no matching ']', we assume the '[' is a normal
+	     * character.  This makes 'incsearch' and ":help [" work.
+	     */
+	    lp = skip_anyof(regparse);
+	    if (*lp == ']')	/* there is a matching ']' */
+	    {
+		int	startc = -1;	/* > 0 when next '-' is a range */
+		int	endc;
+
+		/*
+		 * In a character class, different parsing rules apply.
+		 * Not even \ is special anymore, nothing is.
+		 */
+		if (*regparse == '^')	    /* Complement of range. */
+		{
+		    ret = regnode(ANYBUT + extra);
+		    regparse++;
+		}
+		else
+		    ret = regnode(ANYOF + extra);
+
+		/* At the start ']' and '-' mean the literal character. */
+		if (*regparse == ']' || *regparse == '-')
+		{
+		    startc = *regparse;
+		    regc(*regparse++);
+		}
+
+		while (*regparse != NUL && *regparse != ']')
+		{
+		    if (*regparse == '-')
+		    {
+			++regparse;
+			/* The '-' is not used for a range at the end and
+			 * after or before a '\n'. */
+			if (*regparse == ']' || *regparse == NUL
+				|| startc == -1
+				|| (regparse[0] == '\\' && regparse[1] == 'n'))
+			{
+			    regc('-');
+			    startc = '-';	/* [--x] is a range */
+			}
+			else
+			{
+			    /* Also accept "a-[.z.]" */
+			    endc = 0;
+			    if (*regparse == '[')
+				endc = get_coll_element(&regparse);
+			    if (endc == 0)
+			    {
+				if (has_mbyte)
+				    endc = mb_ptr2char_adv(&regparse);
+				else
+				    endc = *regparse++;
+			    }
+
+			    /* Handle \o40, \x20 and \u20AC style sequences */
+			    if (endc == '\\' && !reg_cpo_lit && !reg_cpo_bsl)
+				endc = coll_get_char();
+
+			    if (startc > endc)
+				EMSG_RET_NULL(_(e_reverse_range));
+			    if (has_mbyte && ((*mb_char2len)(startc) > 1
+						 || (*mb_char2len)(endc) > 1))
+			    {
+				/* Limit to a range of 256 chars. */
+				if (endc > startc + 256)
+				    EMSG_RET_NULL(_(e_large_class));
+				while (++startc <= endc)
+				    regmbc(startc);
+			    }
+			    else
+			    {
+#ifdef EBCDIC
+				int	alpha_only = FALSE;
+
+				/* for alphabetical range skip the gaps
+				 * 'i'-'j', 'r'-'s', 'I'-'J' and 'R'-'S'.  */
+				if (isalpha(startc) && isalpha(endc))
+				    alpha_only = TRUE;
+#endif
+				while (++startc <= endc)
+#ifdef EBCDIC
+				    if (!alpha_only || isalpha(startc))
+#endif
+					regc(startc);
+			    }
+			    startc = -1;
+			}
+		    }
+		    /*
+		     * Only "\]", "\^", "\]" and "\\" are special in Vi.  Vim
+		     * accepts "\t", "\e", etc., but only when the 'l' flag in
+		     * 'cpoptions' is not included.
+		     * Posix doesn't recognize backslash at all.
+		     */
+		    else if (*regparse == '\\'
+			    && !reg_cpo_bsl
+			    && (vim_strchr(REGEXP_INRANGE, regparse[1]) != NULL
+				|| (!reg_cpo_lit
+				    && vim_strchr(REGEXP_ABBR,
+						       regparse[1]) != NULL)))
+		    {
+			regparse++;
+			if (*regparse == 'n')
+			{
+			    /* '\n' in range: also match NL */
+			    if (ret != JUST_CALC_SIZE)
+			    {
+				/* Using \n inside [^] does not change what
+				 * matches. "[^\n]" is the same as ".". */
+				if (*ret == ANYOF)
+				{
+				    *ret = ANYOF + ADD_NL;
+				    *flagp |= HASNL;
+				}
+				/* else: must have had a \n already */
+			    }
+			    regparse++;
+			    startc = -1;
+			}
+			else if (*regparse == 'd'
+				|| *regparse == 'o'
+				|| *regparse == 'x'
+				|| *regparse == 'u'
+				|| *regparse == 'U')
+			{
+			    startc = coll_get_char();
+			    if (startc == 0)
+				regc(0x0a);
+			    else
+				regmbc(startc);
+			}
+			else
+			{
+			    startc = backslash_trans(*regparse++);
+			    regc(startc);
+			}
+		    }
+		    else if (*regparse == '[')
+		    {
+			int c_class;
+			int cu;
+
+			c_class = get_char_class(&regparse);
+			startc = -1;
+			/* Characters assumed to be 8 bits! */
+			switch (c_class)
+			{
+			    case CLASS_NONE:
+				c_class = get_equi_class(&regparse);
+				if (c_class != 0)
+				{
+				    /* produce equivalence class */
+				    reg_equi_class(c_class);
+				}
+				else if ((c_class =
+					    get_coll_element(&regparse)) != 0)
+				{
+				    /* produce a collating element */
+				    regmbc(c_class);
+				}
+				else
+				{
+				    /* literal '[', allow [[-x] as a range */
+				    startc = *regparse++;
+				    regc(startc);
+				}
+				break;
+			    case CLASS_ALNUM:
+				for (cu = 1; cu < 128; cu++)
+				    if (isalnum(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_ALPHA:
+				for (cu = 1; cu < 128; cu++)
+				    if (isalpha(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_BLANK:
+				regc(' ');
+				regc('\t');
+				break;
+			    case CLASS_CNTRL:
+				for (cu = 1; cu <= 127; cu++)
+				    if (iscntrl(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_DIGIT:
+				for (cu = 1; cu <= 127; cu++)
+				    if (VIM_ISDIGIT(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_GRAPH:
+				for (cu = 1; cu <= 127; cu++)
+				    if (isgraph(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_LOWER:
+				for (cu = 1; cu <= 255; cu++)
+				    if (MB_ISLOWER(cu) && cu != 170
+								 && cu != 186)
+					regmbc(cu);
+				break;
+			    case CLASS_PRINT:
+				for (cu = 1; cu <= 255; cu++)
+				    if (vim_isprintc(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_PUNCT:
+				for (cu = 1; cu < 128; cu++)
+				    if (ispunct(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_SPACE:
+				for (cu = 9; cu <= 13; cu++)
+				    regc(cu);
+				regc(' ');
+				break;
+			    case CLASS_UPPER:
+				for (cu = 1; cu <= 255; cu++)
+				    if (MB_ISUPPER(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_XDIGIT:
+				for (cu = 1; cu <= 255; cu++)
+				    if (vim_isxdigit(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_TAB:
+				regc('\t');
+				break;
+			    case CLASS_RETURN:
+				regc('\r');
+				break;
+			    case CLASS_BACKSPACE:
+				regc('\b');
+				break;
+			    case CLASS_ESCAPE:
+				regc('\033');
+				break;
+			    case CLASS_IDENT:
+				for (cu = 1; cu <= 255; cu++)
+				    if (vim_isIDc(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_KEYWORD:
+				for (cu = 1; cu <= 255; cu++)
+				    if (reg_iswordc(cu))
+					regmbc(cu);
+				break;
+			    case CLASS_FNAME:
+				for (cu = 1; cu <= 255; cu++)
+				    if (vim_isfilec(cu))
+					regmbc(cu);
+				break;
+			}
+		    }
+		    else
+		    {
+			if (has_mbyte)
+			{
+			    int	len;
+
+			    /* produce a multibyte character, including any
+			     * following composing characters */
+			    startc = mb_ptr2char(regparse);
+			    len = (*mb_ptr2len)(regparse);
+			    if (enc_utf8 && utf_char2len(startc) != len)
+				startc = -1;	/* composing chars */
+			    while (--len >= 0)
+				regc(*regparse++);
+			}
+			else
+			{
+			    startc = *regparse++;
+			    regc(startc);
+			}
+		    }
+		}
+		regc(NUL);
+		prevchr_len = 1;	/* last char was the ']' */
+		if (*regparse != ']')
+		    EMSG_RET_NULL(_(e_toomsbra));	/* Cannot happen? */
+		skipchr();	    /* let's be friends with the lexer again */
+		*flagp |= HASWIDTH | SIMPLE;
+		break;
+	    }
+	    else if (reg_strict)
+		EMSG2_RET_NULL(_(e_missingbracket), reg_magic > MAGIC_OFF);
+	}
+	/* FALLTHROUGH */
+
+      default:
+	{
+	    int		len;
+
+	    /* A multi-byte character is handled as a separate atom if it's
+	     * before a multi and when it's a composing char. */
+	    if (use_multibytecode(c))
+	    {
+do_multibyte:
+		ret = regnode(MULTIBYTECODE);
+		regmbc(c);
+		*flagp |= HASWIDTH | SIMPLE;
+		break;
+	    }
+
+	    ret = regnode(EXACTLY);
+
+	    /*
+	     * Append characters as long as:
+	     * - there is no following multi, we then need the character in
+	     *   front of it as a single character operand
+	     * - not running into a Magic character
+	     * - "one_exactly" is not set
+	     * But always emit at least one character.  Might be a Multi,
+	     * e.g., a "[" without matching "]".
+	     */
+	    for (len = 0; c != NUL && (len == 0
+			|| (re_multi_type(peekchr()) == NOT_MULTI
+			    && !one_exactly
+			    && !is_Magic(c))); ++len)
+	    {
+		c = no_Magic(c);
+		if (has_mbyte)
+		{
+		    regmbc(c);
+		    if (enc_utf8)
+		    {
+			int	l;
+
+			/* Need to get composing character too. */
+			for (;;)
+			{
+			    l = utf_ptr2len(regparse);
+			    if (!UTF_COMPOSINGLIKE(regparse, regparse + l))
+				break;
+			    regmbc(utf_ptr2char(regparse));
+			    skipchr();
+			}
+		    }
+		}
+		else
+		    regc(c);
+		c = getchr();
+	    }
+	    ungetchr();
+
+	    regc(NUL);
+	    *flagp |= HASWIDTH;
+	    if (len == 1)
+		*flagp |= SIMPLE;
+	}
+	break;
+    }
+
+    return ret;
+}
+
+/*
+ * Parse something followed by possible [*+=].
+ *
+ * Note that the branching code sequences used for = and the general cases
+ * of * and + are somewhat optimized:  they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+    static char_u *
+regpiece(int *flagp)
+{
+    char_u	    *ret;
+    int		    op;
+    char_u	    *next;
+    int		    flags;
+    long	    minval;
+    long	    maxval;
+
+    ret = regatom(&flags);
+    if (ret == NULL)
+	return NULL;
+
+    op = peekchr();
+    if (re_multi_type(op) == NOT_MULTI)
+    {
+	*flagp = flags;
+	return ret;
+    }
+    /* default flags */
+    *flagp = (WORST | SPSTART | (flags & (HASNL | HASLOOKBH)));
+
+    skipchr();
+    switch (op)
+    {
+	case Magic('*'):
+	    if (flags & SIMPLE)
+		reginsert(STAR, ret);
+	    else
+	    {
+		/* Emit x* as (x&|), where & means "self". */
+		reginsert(BRANCH, ret); /* Either x */
+		regoptail(ret, regnode(BACK));	/* and loop */
+		regoptail(ret, ret);	/* back */
+		regtail(ret, regnode(BRANCH));	/* or */
+		regtail(ret, regnode(NOTHING)); /* null. */
+	    }
+	    break;
+
+	case Magic('+'):
+	    if (flags & SIMPLE)
+		reginsert(PLUS, ret);
+	    else
+	    {
+		/* Emit x+ as x(&|), where & means "self". */
+		next = regnode(BRANCH); /* Either */
+		regtail(ret, next);
+		regtail(regnode(BACK), ret);	/* loop back */
+		regtail(next, regnode(BRANCH)); /* or */
+		regtail(ret, regnode(NOTHING)); /* null. */
+	    }
+	    *flagp = (WORST | HASWIDTH | (flags & (HASNL | HASLOOKBH)));
+	    break;
+
+	case Magic('@'):
+	    {
+		int	lop = END;
+		long	nr;
+
+		nr = getdecchrs();
+		switch (no_Magic(getchr()))
+		{
+		    case '=': lop = MATCH; break;		  /* \@= */
+		    case '!': lop = NOMATCH; break;		  /* \@! */
+		    case '>': lop = SUBPAT; break;		  /* \@> */
+		    case '<': switch (no_Magic(getchr()))
+			      {
+				  case '=': lop = BEHIND; break;   /* \@<= */
+				  case '!': lop = NOBEHIND; break; /* \@<! */
+			      }
+		}
+		if (lop == END)
+		    EMSG2_RET_NULL(_("E59: invalid character after %s@"),
+						      reg_magic == MAGIC_ALL);
+		/* Look behind must match with behind_pos. */
+		if (lop == BEHIND || lop == NOBEHIND)
+		{
+		    regtail(ret, regnode(BHPOS));
+		    *flagp |= HASLOOKBH;
+		}
+		regtail(ret, regnode(END)); /* operand ends */
+		if (lop == BEHIND || lop == NOBEHIND)
+		{
+		    if (nr < 0)
+			nr = 0; /* no limit is same as zero limit */
+		    reginsert_nr(lop, nr, ret);
+		}
+		else
+		    reginsert(lop, ret);
+		break;
+	    }
+
+	case Magic('?'):
+	case Magic('='):
+	    /* Emit x= as (x|) */
+	    reginsert(BRANCH, ret);		/* Either x */
+	    regtail(ret, regnode(BRANCH));	/* or */
+	    next = regnode(NOTHING);		/* null. */
+	    regtail(ret, next);
+	    regoptail(ret, next);
+	    break;
+
+	case Magic('{'):
+	    if (!read_limits(&minval, &maxval))
+		return NULL;
+	    if (flags & SIMPLE)
+	    {
+		reginsert(BRACE_SIMPLE, ret);
+		reginsert_limits(BRACE_LIMITS, minval, maxval, ret);
+	    }
+	    else
+	    {
+		if (num_complex_braces >= 10)
+		    EMSG2_RET_NULL(_("E60: Too many complex %s{...}s"),
+						      reg_magic == MAGIC_ALL);
+		reginsert(BRACE_COMPLEX + num_complex_braces, ret);
+		regoptail(ret, regnode(BACK));
+		regoptail(ret, ret);
+		reginsert_limits(BRACE_LIMITS, minval, maxval, ret);
+		++num_complex_braces;
+	    }
+	    if (minval > 0 && maxval > 0)
+		*flagp = (HASWIDTH | (flags & (HASNL | HASLOOKBH)));
+	    break;
+    }
+    if (re_multi_type(peekchr()) != NOT_MULTI)
+    {
+	// Can't have a multi follow a multi.
+	if (peekchr() == Magic('*'))
+	    EMSG2_RET_NULL(_("E61: Nested %s*"), reg_magic >= MAGIC_ON);
+	EMSG3_RET_NULL(_("E62: Nested %s%c"), reg_magic == MAGIC_ALL,
+							  no_Magic(peekchr()));
+    }
+
+    return ret;
+}
+
+/*
+ * Parse one alternative of an | or & operator.
+ * Implements the concatenation operator.
+ */
+    static char_u *
+regconcat(int *flagp)
+{
+    char_u	*first = NULL;
+    char_u	*chain = NULL;
+    char_u	*latest;
+    int		flags;
+    int		cont = TRUE;
+
+    *flagp = WORST;		/* Tentatively. */
+
+    while (cont)
+    {
+	switch (peekchr())
+	{
+	    case NUL:
+	    case Magic('|'):
+	    case Magic('&'):
+	    case Magic(')'):
+			    cont = FALSE;
+			    break;
+	    case Magic('Z'):
+			    regflags |= RF_ICOMBINE;
+			    skipchr_keepstart();
+			    break;
+	    case Magic('c'):
+			    regflags |= RF_ICASE;
+			    skipchr_keepstart();
+			    break;
+	    case Magic('C'):
+			    regflags |= RF_NOICASE;
+			    skipchr_keepstart();
+			    break;
+	    case Magic('v'):
+			    reg_magic = MAGIC_ALL;
+			    skipchr_keepstart();
+			    curchr = -1;
+			    break;
+	    case Magic('m'):
+			    reg_magic = MAGIC_ON;
+			    skipchr_keepstart();
+			    curchr = -1;
+			    break;
+	    case Magic('M'):
+			    reg_magic = MAGIC_OFF;
+			    skipchr_keepstart();
+			    curchr = -1;
+			    break;
+	    case Magic('V'):
+			    reg_magic = MAGIC_NONE;
+			    skipchr_keepstart();
+			    curchr = -1;
+			    break;
+	    default:
+			    latest = regpiece(&flags);
+			    if (latest == NULL || reg_toolong)
+				return NULL;
+			    *flagp |= flags & (HASWIDTH | HASNL | HASLOOKBH);
+			    if (chain == NULL)	/* First piece. */
+				*flagp |= flags & SPSTART;
+			    else
+				regtail(chain, latest);
+			    chain = latest;
+			    if (first == NULL)
+				first = latest;
+			    break;
+	}
+    }
+    if (first == NULL)		/* Loop ran zero times. */
+	first = regnode(NOTHING);
+    return first;
+}
+
+/*
+ * Parse one alternative of an | operator.
+ * Implements the & operator.
+ */
+    static char_u *
+regbranch(int *flagp)
+{
+    char_u	*ret;
+    char_u	*chain = NULL;
+    char_u	*latest;
+    int		flags;
+
+    *flagp = WORST | HASNL;		/* Tentatively. */
+
+    ret = regnode(BRANCH);
+    for (;;)
+    {
+	latest = regconcat(&flags);
+	if (latest == NULL)
+	    return NULL;
+	/* If one of the branches has width, the whole thing has.  If one of
+	 * the branches anchors at start-of-line, the whole thing does.
+	 * If one of the branches uses look-behind, the whole thing does. */
+	*flagp |= flags & (HASWIDTH | SPSTART | HASLOOKBH);
+	/* If one of the branches doesn't match a line-break, the whole thing
+	 * doesn't. */
+	*flagp &= ~HASNL | (flags & HASNL);
+	if (chain != NULL)
+	    regtail(chain, latest);
+	if (peekchr() != Magic('&'))
+	    break;
+	skipchr();
+	regtail(latest, regnode(END)); /* operand ends */
+	if (reg_toolong)
+	    break;
+	reginsert(MATCH, latest);
+	chain = latest;
+    }
+
+    return ret;
+}
+
+/*
+ * Parse regular expression, i.e. main body or parenthesized thing.
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+    static char_u *
+reg(
+    int		paren,	/* REG_NOPAREN, REG_PAREN, REG_NPAREN or REG_ZPAREN */
+    int		*flagp)
+{
+    char_u	*ret;
+    char_u	*br;
+    char_u	*ender;
+    int		parno = 0;
+    int		flags;
+
+    *flagp = HASWIDTH;		/* Tentatively. */
+
+#ifdef FEAT_SYN_HL
+    if (paren == REG_ZPAREN)
+    {
+	/* Make a ZOPEN node. */
+	if (regnzpar >= NSUBEXP)
+	    EMSG_RET_NULL(_("E50: Too many \\z("));
+	parno = regnzpar;
+	regnzpar++;
+	ret = regnode(ZOPEN + parno);
+    }
+    else
+#endif
+	if (paren == REG_PAREN)
+    {
+	/* Make a MOPEN node. */
+	if (regnpar >= NSUBEXP)
+	    EMSG2_RET_NULL(_("E51: Too many %s("), reg_magic == MAGIC_ALL);
+	parno = regnpar;
+	++regnpar;
+	ret = regnode(MOPEN + parno);
+    }
+    else if (paren == REG_NPAREN)
+    {
+	/* Make a NOPEN node. */
+	ret = regnode(NOPEN);
+    }
+    else
+	ret = NULL;
+
+    /* Pick up the branches, linking them together. */
+    br = regbranch(&flags);
+    if (br == NULL)
+	return NULL;
+    if (ret != NULL)
+	regtail(ret, br);	/* [MZ]OPEN -> first. */
+    else
+	ret = br;
+    /* If one of the branches can be zero-width, the whole thing can.
+     * If one of the branches has * at start or matches a line-break, the
+     * whole thing can. */
+    if (!(flags & HASWIDTH))
+	*flagp &= ~HASWIDTH;
+    *flagp |= flags & (SPSTART | HASNL | HASLOOKBH);
+    while (peekchr() == Magic('|'))
+    {
+	skipchr();
+	br = regbranch(&flags);
+	if (br == NULL || reg_toolong)
+	    return NULL;
+	regtail(ret, br);	/* BRANCH -> BRANCH. */
+	if (!(flags & HASWIDTH))
+	    *flagp &= ~HASWIDTH;
+	*flagp |= flags & (SPSTART | HASNL | HASLOOKBH);
+    }
+
+    /* Make a closing node, and hook it on the end. */
+    ender = regnode(
+#ifdef FEAT_SYN_HL
+	    paren == REG_ZPAREN ? ZCLOSE + parno :
+#endif
+	    paren == REG_PAREN ? MCLOSE + parno :
+	    paren == REG_NPAREN ? NCLOSE : END);
+    regtail(ret, ender);
+
+    /* Hook the tails of the branches to the closing node. */
+    for (br = ret; br != NULL; br = regnext(br))
+	regoptail(br, ender);
+
+    /* Check for proper termination. */
+    if (paren != REG_NOPAREN && getchr() != Magic(')'))
+    {
+#ifdef FEAT_SYN_HL
+	if (paren == REG_ZPAREN)
+	    EMSG_RET_NULL(_("E52: Unmatched \\z("));
+	else
+#endif
+	    if (paren == REG_NPAREN)
+	    EMSG2_RET_NULL(_(e_unmatchedpp), reg_magic == MAGIC_ALL);
+	else
+	    EMSG2_RET_NULL(_(e_unmatchedp), reg_magic == MAGIC_ALL);
+    }
+    else if (paren == REG_NOPAREN && peekchr() != NUL)
+    {
+	if (curchr == Magic(')'))
+	    EMSG2_RET_NULL(_(e_unmatchedpar), reg_magic == MAGIC_ALL);
+	else
+	    EMSG_RET_NULL(_(e_trailing));	/* "Can't happen". */
+	/* NOTREACHED */
+    }
+    /*
+     * Here we set the flag allowing back references to this set of
+     * parentheses.
+     */
+    if (paren == REG_PAREN)
+	had_endbrace[parno] = TRUE;	/* have seen the close paren */
+    return ret;
+}
+
+/*
+ * bt_regcomp() - compile a regular expression into internal code for the
+ * traditional back track matcher.
+ * Returns the program in allocated space.  Returns NULL for an error.
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code.  So we cheat:  we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it.  (Note that it has to be in
+ * one piece because vim_free() must be able to free it all.)
+ *
+ * Whether upper/lower case is to be ignored is decided when executing the
+ * program, it does not matter here.
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ * "re_flags": RE_MAGIC and/or RE_STRING.
+ */
+    static regprog_T *
+bt_regcomp(char_u *expr, int re_flags)
+{
+    bt_regprog_T    *r;
+    char_u	*scan;
+    char_u	*longest;
+    int		len;
+    int		flags;
+
+    if (expr == NULL)
+	EMSG_RET_NULL(_(e_null));
+
+    init_class_tab();
+
+    // First pass: determine size, legality.
+    regcomp_start(expr, re_flags);
+    regcode = JUST_CALC_SIZE;
+    regc(REGMAGIC);
+    if (reg(REG_NOPAREN, &flags) == NULL)
+	return NULL;
+
+    // Allocate space.
+    r = alloc(offsetof(bt_regprog_T, program) + regsize);
+    if (r == NULL)
+	return NULL;
+    r->re_in_use = FALSE;
+
+    // Second pass: emit code.
+    regcomp_start(expr, re_flags);
+    regcode = r->program;
+    regc(REGMAGIC);
+    if (reg(REG_NOPAREN, &flags) == NULL || reg_toolong)
+    {
+	vim_free(r);
+	if (reg_toolong)
+	    EMSG_RET_NULL(_("E339: Pattern too long"));
+	return NULL;
+    }
+
+    // Dig out information for optimizations.
+    r->regstart = NUL;		// Worst-case defaults.
+    r->reganch = 0;
+    r->regmust = NULL;
+    r->regmlen = 0;
+    r->regflags = regflags;
+    if (flags & HASNL)
+	r->regflags |= RF_HASNL;
+    if (flags & HASLOOKBH)
+	r->regflags |= RF_LOOKBH;
+#ifdef FEAT_SYN_HL
+    // Remember whether this pattern has any \z specials in it.
+    r->reghasz = re_has_z;
+#endif
+    scan = r->program + 1;	// First BRANCH.
+    if (OP(regnext(scan)) == END)   // Only one top-level choice.
+    {
+	scan = OPERAND(scan);
+
+	// Starting-point info.
+	if (OP(scan) == BOL || OP(scan) == RE_BOF)
+	{
+	    r->reganch++;
+	    scan = regnext(scan);
+	}
+
+	if (OP(scan) == EXACTLY)
+	{
+	    if (has_mbyte)
+		r->regstart = (*mb_ptr2char)(OPERAND(scan));
+	    else
+		r->regstart = *OPERAND(scan);
+	}
+	else if ((OP(scan) == BOW
+		    || OP(scan) == EOW
+		    || OP(scan) == NOTHING
+		    || OP(scan) == MOPEN + 0 || OP(scan) == NOPEN
+		    || OP(scan) == MCLOSE + 0 || OP(scan) == NCLOSE)
+		 && OP(regnext(scan)) == EXACTLY)
+	{
+	    if (has_mbyte)
+		r->regstart = (*mb_ptr2char)(OPERAND(regnext(scan)));
+	    else
+		r->regstart = *OPERAND(regnext(scan));
+	}
+
+	// If there's something expensive in the r.e., find the longest
+	// literal string that must appear and make it the regmust.  Resolve
+	// ties in favor of later strings, since the regstart check works
+	// with the beginning of the r.e. and avoiding duplication
+	// strengthens checking.  Not a strong reason, but sufficient in the
+	// absence of others.
+
+	// When the r.e. starts with BOW, it is faster to look for a regmust
+	// first. Used a lot for "#" and "*" commands. (Added by mool).
+	if ((flags & SPSTART || OP(scan) == BOW || OP(scan) == EOW)
+							  && !(flags & HASNL))
+	{
+	    longest = NULL;
+	    len = 0;
+	    for (; scan != NULL; scan = regnext(scan))
+		if (OP(scan) == EXACTLY && STRLEN(OPERAND(scan)) >= (size_t)len)
+		{
+		    longest = OPERAND(scan);
+		    len = (int)STRLEN(OPERAND(scan));
+		}
+	    r->regmust = longest;
+	    r->regmlen = len;
+	}
+    }
+#ifdef BT_REGEXP_DUMP
+    regdump(expr, r);
+#endif
+    r->engine = &bt_regengine;
+    return (regprog_T *)r;
+}
+
+#if defined(FEAT_SYN_HL) || defined(PROTO)
+/*
+ * Check if during the previous call to vim_regcomp the EOL item "$" has been
+ * found.  This is messy, but it works fine.
+ */
+    int
+vim_regcomp_had_eol(void)
+{
+    return had_eol;
+}
+#endif
+
+/*
+ * Get a number after a backslash that is inside [].
+ * When nothing is recognized return a backslash.
+ */
+    static int
+coll_get_char(void)
+{
+    long	nr = -1;
+
+    switch (*regparse++)
+    {
+	case 'd': nr = getdecchrs(); break;
+	case 'o': nr = getoctchrs(); break;
+	case 'x': nr = gethexchrs(2); break;
+	case 'u': nr = gethexchrs(4); break;
+	case 'U': nr = gethexchrs(8); break;
+    }
+    if (nr < 0 || nr > INT_MAX)
+    {
+	/* If getting the number fails be backwards compatible: the character
+	 * is a backslash. */
+	--regparse;
+	nr = '\\';
+    }
+    return nr;
+}
+
+/*
+ * Free a compiled regexp program, returned by bt_regcomp().
+ */
+    static void
+bt_regfree(regprog_T *prog)
+{
+    vim_free(prog);
+}
+
+#define ADVANCE_REGINPUT() MB_PTR_ADV(rex.input)
+
+/*
+ * The arguments from BRACE_LIMITS are stored here.  They are actually local
+ * to regmatch(), but they are here to reduce the amount of stack space used
+ * (it can be called recursively many times).
+ */
+static long	bl_minval;
+static long	bl_maxval;
+
+/*
+ * Save the input line and position in a regsave_T.
+ */
+    static void
+reg_save(regsave_T *save, garray_T *gap)
+{
+    if (REG_MULTI)
+    {
+	save->rs_u.pos.col = (colnr_T)(rex.input - rex.line);
+	save->rs_u.pos.lnum = rex.lnum;
+    }
+    else
+	save->rs_u.ptr = rex.input;
+    save->rs_len = gap->ga_len;
+}
+
+/*
+ * Restore the input line and position from a regsave_T.
+ */
+    static void
+reg_restore(regsave_T *save, garray_T *gap)
+{
+    if (REG_MULTI)
+    {
+	if (rex.lnum != save->rs_u.pos.lnum)
+	{
+	    /* only call reg_getline() when the line number changed to save
+	     * a bit of time */
+	    rex.lnum = save->rs_u.pos.lnum;
+	    rex.line = reg_getline(rex.lnum);
+	}
+	rex.input = rex.line + save->rs_u.pos.col;
+    }
+    else
+	rex.input = save->rs_u.ptr;
+    gap->ga_len = save->rs_len;
+}
+
+/*
+ * Return TRUE if current position is equal to saved position.
+ */
+    static int
+reg_save_equal(regsave_T *save)
+{
+    if (REG_MULTI)
+	return rex.lnum == save->rs_u.pos.lnum
+				  && rex.input == rex.line + save->rs_u.pos.col;
+    return rex.input == save->rs_u.ptr;
+}
+
+/* Save the sub-expressions before attempting a match. */
+#define save_se(savep, posp, pp) \
+    REG_MULTI ? save_se_multi((savep), (posp)) : save_se_one((savep), (pp))
+
+/* After a failed match restore the sub-expressions. */
+#define restore_se(savep, posp, pp) { \
+    if (REG_MULTI) \
+	*(posp) = (savep)->se_u.pos; \
+    else \
+	*(pp) = (savep)->se_u.ptr; }
+
+/*
+ * Tentatively set the sub-expression start to the current position (after
+ * calling regmatch() they will have changed).  Need to save the existing
+ * values for when there is no match.
+ * Use se_save() to use pointer (save_se_multi()) or position (save_se_one()),
+ * depending on REG_MULTI.
+ */
+    static void
+save_se_multi(save_se_T *savep, lpos_T *posp)
+{
+    savep->se_u.pos = *posp;
+    posp->lnum = rex.lnum;
+    posp->col = (colnr_T)(rex.input - rex.line);
+}
+
+    static void
+save_se_one(save_se_T *savep, char_u **pp)
+{
+    savep->se_u.ptr = *pp;
+    *pp = rex.input;
+}
+
+/*
+ * regrepeat - repeatedly match something simple, return how many.
+ * Advances rex.input (and rex.lnum) to just after the matched chars.
+ */
+    static int
+regrepeat(
+    char_u	*p,
+    long	maxcount)   /* maximum number of matches allowed */
+{
+    long	count = 0;
+    char_u	*scan;
+    char_u	*opnd;
+    int		mask;
+    int		testval = 0;
+
+    scan = rex.input;	    /* Make local copy of rex.input for speed. */
+    opnd = OPERAND(p);
+    switch (OP(p))
+    {
+      case ANY:
+      case ANY + ADD_NL:
+	while (count < maxcount)
+	{
+	    /* Matching anything means we continue until end-of-line (or
+	     * end-of-file for ANY + ADD_NL), only limited by maxcount. */
+	    while (*scan != NUL && count < maxcount)
+	    {
+		++count;
+		MB_PTR_ADV(scan);
+	    }
+	    if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+				      || rex.reg_line_lbr || count == maxcount)
+		break;
+	    ++count;		/* count the line-break */
+	    reg_nextline();
+	    scan = rex.input;
+	    if (got_int)
+		break;
+	}
+	break;
+
+      case IDENT:
+      case IDENT + ADD_NL:
+	testval = TRUE;
+	/* FALLTHROUGH */
+      case SIDENT:
+      case SIDENT + ADD_NL:
+	while (count < maxcount)
+	{
+	    if (vim_isIDc(PTR2CHAR(scan)) && (testval || !VIM_ISDIGIT(*scan)))
+	    {
+		MB_PTR_ADV(scan);
+	    }
+	    else if (*scan == NUL)
+	    {
+		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+							   || rex.reg_line_lbr)
+		    break;
+		reg_nextline();
+		scan = rex.input;
+		if (got_int)
+		    break;
+	    }
+	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+		++scan;
+	    else
+		break;
+	    ++count;
+	}
+	break;
+
+      case KWORD:
+      case KWORD + ADD_NL:
+	testval = TRUE;
+	/* FALLTHROUGH */
+      case SKWORD:
+      case SKWORD + ADD_NL:
+	while (count < maxcount)
+	{
+	    if (vim_iswordp_buf(scan, rex.reg_buf)
+					  && (testval || !VIM_ISDIGIT(*scan)))
+	    {
+		MB_PTR_ADV(scan);
+	    }
+	    else if (*scan == NUL)
+	    {
+		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+							   || rex.reg_line_lbr)
+		    break;
+		reg_nextline();
+		scan = rex.input;
+		if (got_int)
+		    break;
+	    }
+	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+		++scan;
+	    else
+		break;
+	    ++count;
+	}
+	break;
+
+      case FNAME:
+      case FNAME + ADD_NL:
+	testval = TRUE;
+	/* FALLTHROUGH */
+      case SFNAME:
+      case SFNAME + ADD_NL:
+	while (count < maxcount)
+	{
+	    if (vim_isfilec(PTR2CHAR(scan)) && (testval || !VIM_ISDIGIT(*scan)))
+	    {
+		MB_PTR_ADV(scan);
+	    }
+	    else if (*scan == NUL)
+	    {
+		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+							   || rex.reg_line_lbr)
+		    break;
+		reg_nextline();
+		scan = rex.input;
+		if (got_int)
+		    break;
+	    }
+	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+		++scan;
+	    else
+		break;
+	    ++count;
+	}
+	break;
+
+      case PRINT:
+      case PRINT + ADD_NL:
+	testval = TRUE;
+	/* FALLTHROUGH */
+      case SPRINT:
+      case SPRINT + ADD_NL:
+	while (count < maxcount)
+	{
+	    if (*scan == NUL)
+	    {
+		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+							   || rex.reg_line_lbr)
+		    break;
+		reg_nextline();
+		scan = rex.input;
+		if (got_int)
+		    break;
+	    }
+	    else if (vim_isprintc(PTR2CHAR(scan)) == 1
+					  && (testval || !VIM_ISDIGIT(*scan)))
+	    {
+		MB_PTR_ADV(scan);
+	    }
+	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+		++scan;
+	    else
+		break;
+	    ++count;
+	}
+	break;
+
+      case WHITE:
+      case WHITE + ADD_NL:
+	testval = mask = RI_WHITE;
+do_class:
+	while (count < maxcount)
+	{
+	    int		l;
+
+	    if (*scan == NUL)
+	    {
+		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+							   || rex.reg_line_lbr)
+		    break;
+		reg_nextline();
+		scan = rex.input;
+		if (got_int)
+		    break;
+	    }
+	    else if (has_mbyte && (l = (*mb_ptr2len)(scan)) > 1)
+	    {
+		if (testval != 0)
+		    break;
+		scan += l;
+	    }
+	    else if ((class_tab[*scan] & mask) == testval)
+		++scan;
+	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+		++scan;
+	    else
+		break;
+	    ++count;
+	}
+	break;
+
+      case NWHITE:
+      case NWHITE + ADD_NL:
+	mask = RI_WHITE;
+	goto do_class;
+      case DIGIT:
+      case DIGIT + ADD_NL:
+	testval = mask = RI_DIGIT;
+	goto do_class;
+      case NDIGIT:
+      case NDIGIT + ADD_NL:
+	mask = RI_DIGIT;
+	goto do_class;
+      case HEX:
+      case HEX + ADD_NL:
+	testval = mask = RI_HEX;
+	goto do_class;
+      case NHEX:
+      case NHEX + ADD_NL:
+	mask = RI_HEX;
+	goto do_class;
+      case OCTAL:
+      case OCTAL + ADD_NL:
+	testval = mask = RI_OCTAL;
+	goto do_class;
+      case NOCTAL:
+      case NOCTAL + ADD_NL:
+	mask = RI_OCTAL;
+	goto do_class;
+      case WORD:
+      case WORD + ADD_NL:
+	testval = mask = RI_WORD;
+	goto do_class;
+      case NWORD:
+      case NWORD + ADD_NL:
+	mask = RI_WORD;
+	goto do_class;
+      case HEAD:
+      case HEAD + ADD_NL:
+	testval = mask = RI_HEAD;
+	goto do_class;
+      case NHEAD:
+      case NHEAD + ADD_NL:
+	mask = RI_HEAD;
+	goto do_class;
+      case ALPHA:
+      case ALPHA + ADD_NL:
+	testval = mask = RI_ALPHA;
+	goto do_class;
+      case NALPHA:
+      case NALPHA + ADD_NL:
+	mask = RI_ALPHA;
+	goto do_class;
+      case LOWER:
+      case LOWER + ADD_NL:
+	testval = mask = RI_LOWER;
+	goto do_class;
+      case NLOWER:
+      case NLOWER + ADD_NL:
+	mask = RI_LOWER;
+	goto do_class;
+      case UPPER:
+      case UPPER + ADD_NL:
+	testval = mask = RI_UPPER;
+	goto do_class;
+      case NUPPER:
+      case NUPPER + ADD_NL:
+	mask = RI_UPPER;
+	goto do_class;
+
+      case EXACTLY:
+	{
+	    int	    cu, cl;
+
+	    /* This doesn't do a multi-byte character, because a MULTIBYTECODE
+	     * would have been used for it.  It does handle single-byte
+	     * characters, such as latin1. */
+	    if (rex.reg_ic)
+	    {
+		cu = MB_TOUPPER(*opnd);
+		cl = MB_TOLOWER(*opnd);
+		while (count < maxcount && (*scan == cu || *scan == cl))
+		{
+		    count++;
+		    scan++;
+		}
+	    }
+	    else
+	    {
+		cu = *opnd;
+		while (count < maxcount && *scan == cu)
+		{
+		    count++;
+		    scan++;
+		}
+	    }
+	    break;
+	}
+
+      case MULTIBYTECODE:
+	{
+	    int		i, len, cf = 0;
+
+	    /* Safety check (just in case 'encoding' was changed since
+	     * compiling the program). */
+	    if ((len = (*mb_ptr2len)(opnd)) > 1)
+	    {
+		if (rex.reg_ic && enc_utf8)
+		    cf = utf_fold(utf_ptr2char(opnd));
+		while (count < maxcount && (*mb_ptr2len)(scan) >= len)
+		{
+		    for (i = 0; i < len; ++i)
+			if (opnd[i] != scan[i])
+			    break;
+		    if (i < len && (!rex.reg_ic || !enc_utf8
+					|| utf_fold(utf_ptr2char(scan)) != cf))
+			break;
+		    scan += len;
+		    ++count;
+		}
+	    }
+	}
+	break;
+
+      case ANYOF:
+      case ANYOF + ADD_NL:
+	testval = TRUE;
+	/* FALLTHROUGH */
+
+      case ANYBUT:
+      case ANYBUT + ADD_NL:
+	while (count < maxcount)
+	{
+	    int len;
+
+	    if (*scan == NUL)
+	    {
+		if (!REG_MULTI || !WITH_NL(OP(p)) || rex.lnum > rex.reg_maxline
+							   || rex.reg_line_lbr)
+		    break;
+		reg_nextline();
+		scan = rex.input;
+		if (got_int)
+		    break;
+	    }
+	    else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p)))
+		++scan;
+	    else if (has_mbyte && (len = (*mb_ptr2len)(scan)) > 1)
+	    {
+		if ((cstrchr(opnd, (*mb_ptr2char)(scan)) == NULL) == testval)
+		    break;
+		scan += len;
+	    }
+	    else
+	    {
+		if ((cstrchr(opnd, *scan) == NULL) == testval)
+		    break;
+		++scan;
+	    }
+	    ++count;
+	}
+	break;
+
+      case NEWL:
+	while (count < maxcount
+		&& ((*scan == NUL && rex.lnum <= rex.reg_maxline
+				       && !rex.reg_line_lbr && REG_MULTI)
+		    || (*scan == '\n' && rex.reg_line_lbr)))
+	{
+	    count++;
+	    if (rex.reg_line_lbr)
+		ADVANCE_REGINPUT();
+	    else
+		reg_nextline();
+	    scan = rex.input;
+	    if (got_int)
+		break;
+	}
+	break;
+
+      default:			/* Oh dear.  Called inappropriately. */
+	emsg(_(e_re_corr));
+#ifdef DEBUG
+	printf("Called regrepeat with op code %d\n", OP(p));
+#endif
+	break;
+    }
+
+    rex.input = scan;
+
+    return (int)count;
+}
+
+/*
+ * Push an item onto the regstack.
+ * Returns pointer to new item.  Returns NULL when out of memory.
+ */
+    static regitem_T *
+regstack_push(regstate_T state, char_u *scan)
+{
+    regitem_T	*rp;
+
+    if ((long)((unsigned)regstack.ga_len >> 10) >= p_mmp)
+    {
+	emsg(_(e_maxmempat));
+	return NULL;
+    }
+    if (ga_grow(&regstack, sizeof(regitem_T)) == FAIL)
+	return NULL;
+
+    rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len);
+    rp->rs_state = state;
+    rp->rs_scan = scan;
+
+    regstack.ga_len += sizeof(regitem_T);
+    return rp;
+}
+
+/*
+ * Pop an item from the regstack.
+ */
+    static void
+regstack_pop(char_u **scan)
+{
+    regitem_T	*rp;
+
+    rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len) - 1;
+    *scan = rp->rs_scan;
+
+    regstack.ga_len -= sizeof(regitem_T);
+}
+
+/*
+ * Save the current subexpr to "bp", so that they can be restored
+ * later by restore_subexpr().
+ */
+    static void
+save_subexpr(regbehind_T *bp)
+{
+    int i;
+
+    /* When "rex.need_clear_subexpr" is set we don't need to save the values, only
+     * remember that this flag needs to be set again when restoring. */
+    bp->save_need_clear_subexpr = rex.need_clear_subexpr;
+    if (!rex.need_clear_subexpr)
+    {
+	for (i = 0; i < NSUBEXP; ++i)
+	{
+	    if (REG_MULTI)
+	    {
+		bp->save_start[i].se_u.pos = rex.reg_startpos[i];
+		bp->save_end[i].se_u.pos = rex.reg_endpos[i];
+	    }
+	    else
+	    {
+		bp->save_start[i].se_u.ptr = rex.reg_startp[i];
+		bp->save_end[i].se_u.ptr = rex.reg_endp[i];
+	    }
+	}
+    }
+}
+
+/*
+ * Restore the subexpr from "bp".
+ */
+    static void
+restore_subexpr(regbehind_T *bp)
+{
+    int i;
+
+    /* Only need to restore saved values when they are not to be cleared. */
+    rex.need_clear_subexpr = bp->save_need_clear_subexpr;
+    if (!rex.need_clear_subexpr)
+    {
+	for (i = 0; i < NSUBEXP; ++i)
+	{
+	    if (REG_MULTI)
+	    {
+		rex.reg_startpos[i] = bp->save_start[i].se_u.pos;
+		rex.reg_endpos[i] = bp->save_end[i].se_u.pos;
+	    }
+	    else
+	    {
+		rex.reg_startp[i] = bp->save_start[i].se_u.ptr;
+		rex.reg_endp[i] = bp->save_end[i].se_u.ptr;
+	    }
+	}
+    }
+}
+
+/*
+ * regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: Check to see whether the current node
+ * matches, push an item onto the regstack and loop to see whether the rest
+ * matches, and then act accordingly.  In practice we make some effort to
+ * avoid using the regstack, in particular by going through "ordinary" nodes
+ * (that don't need to know whether the rest of the match failed) by a nested
+ * loop.
+ *
+ * Returns TRUE when there is a match.  Leaves rex.input and rex.lnum just after
+ * the last matched character.
+ * Returns FALSE when there is no match.  Leaves rex.input and rex.lnum in an
+ * undefined state!
+ */
+    static int
+regmatch(
+    char_u	*scan,		    /* Current node. */
+    proftime_T	*tm UNUSED,	    /* timeout limit or NULL */
+    int		*timed_out UNUSED)  /* flag set on timeout or NULL */
+{
+  char_u	*next;		/* Next node. */
+  int		op;
+  int		c;
+  regitem_T	*rp;
+  int		no;
+  int		status;		/* one of the RA_ values: */
+#ifdef FEAT_RELTIME
+  int		tm_count = 0;
+#endif
+
+  /* Make "regstack" and "backpos" empty.  They are allocated and freed in
+   * bt_regexec_both() to reduce malloc()/free() calls. */
+  regstack.ga_len = 0;
+  backpos.ga_len = 0;
+
+  /*
+   * Repeat until "regstack" is empty.
+   */
+  for (;;)
+  {
+    /* Some patterns may take a long time to match, e.g., "\([a-z]\+\)\+Q".
+     * Allow interrupting them with CTRL-C. */
+    fast_breakcheck();
+
+#ifdef DEBUG
+    if (scan != NULL && regnarrate)
+    {
+	mch_errmsg((char *)regprop(scan));
+	mch_errmsg("(\n");
+    }
+#endif
+
+    /*
+     * Repeat for items that can be matched sequentially, without using the
+     * regstack.
+     */
+    for (;;)
+    {
+	if (got_int || scan == NULL)
+	{
+	    status = RA_FAIL;
+	    break;
+	}
+#ifdef FEAT_RELTIME
+	/* Check for timeout once in a 100 times to avoid overhead. */
+	if (tm != NULL && ++tm_count == 100)
+	{
+	    tm_count = 0;
+	    if (profile_passed_limit(tm))
+	    {
+		if (timed_out != NULL)
+		    *timed_out = TRUE;
+		status = RA_FAIL;
+		break;
+	    }
+	}
+#endif
+	status = RA_CONT;
+
+#ifdef DEBUG
+	if (regnarrate)
+	{
+	    mch_errmsg((char *)regprop(scan));
+	    mch_errmsg("...\n");
+# ifdef FEAT_SYN_HL
+	    if (re_extmatch_in != NULL)
+	    {
+		int i;
+
+		mch_errmsg(_("External submatches:\n"));
+		for (i = 0; i < NSUBEXP; i++)
+		{
+		    mch_errmsg("    \"");
+		    if (re_extmatch_in->matches[i] != NULL)
+			mch_errmsg((char *)re_extmatch_in->matches[i]);
+		    mch_errmsg("\"\n");
+		}
+	    }
+# endif
+	}
+#endif
+	next = regnext(scan);
+
+	op = OP(scan);
+	/* Check for character class with NL added. */
+	if (!rex.reg_line_lbr && WITH_NL(op) && REG_MULTI
+			     && *rex.input == NUL && rex.lnum <= rex.reg_maxline)
+	{
+	    reg_nextline();
+	}
+	else if (rex.reg_line_lbr && WITH_NL(op) && *rex.input == '\n')
+	{
+	    ADVANCE_REGINPUT();
+	}
+	else
+	{
+	  if (WITH_NL(op))
+	      op -= ADD_NL;
+	  if (has_mbyte)
+	      c = (*mb_ptr2char)(rex.input);
+	  else
+	      c = *rex.input;
+	  switch (op)
+	  {
+	  case BOL:
+	    if (rex.input != rex.line)
+		status = RA_NOMATCH;
+	    break;
+
+	  case EOL:
+	    if (c != NUL)
+		status = RA_NOMATCH;
+	    break;
+
+	  case RE_BOF:
+	    /* We're not at the beginning of the file when below the first
+	     * line where we started, not at the start of the line or we
+	     * didn't start at the first line of the buffer. */
+	    if (rex.lnum != 0 || rex.input != rex.line
+				       || (REG_MULTI && rex.reg_firstlnum > 1))
+		status = RA_NOMATCH;
+	    break;
+
+	  case RE_EOF:
+	    if (rex.lnum != rex.reg_maxline || c != NUL)
+		status = RA_NOMATCH;
+	    break;
+
+	  case CURSOR:
+	    /* Check if the buffer is in a window and compare the
+	     * rex.reg_win->w_cursor position to the match position. */
+	    if (rex.reg_win == NULL
+		    || (rex.lnum + rex.reg_firstlnum
+						 != rex.reg_win->w_cursor.lnum)
+		    || ((colnr_T)(rex.input - rex.line)
+						 != rex.reg_win->w_cursor.col))
+		status = RA_NOMATCH;
+	    break;
+
+	  case RE_MARK:
+	    /* Compare the mark position to the match position. */
+	    {
+		int	mark = OPERAND(scan)[0];
+		int	cmp = OPERAND(scan)[1];
+		pos_T	*pos;
+
+		pos = getmark_buf(rex.reg_buf, mark, FALSE);
+		if (pos == NULL		     /* mark doesn't exist */
+			|| pos->lnum <= 0    /* mark isn't set in reg_buf */
+			|| (pos->lnum == rex.lnum + rex.reg_firstlnum
+				? (pos->col == (colnr_T)(rex.input - rex.line)
+				    ? (cmp == '<' || cmp == '>')
+				    : (pos->col < (colnr_T)(rex.input - rex.line)
+					? cmp != '>'
+					: cmp != '<'))
+				: (pos->lnum < rex.lnum + rex.reg_firstlnum
+				    ? cmp != '>'
+				    : cmp != '<')))
+		    status = RA_NOMATCH;
+	    }
+	    break;
+
+	  case RE_VISUAL:
+	    if (!reg_match_visual())
+		status = RA_NOMATCH;
+	    break;
+
+	  case RE_LNUM:
+	    if (!REG_MULTI || !re_num_cmp((long_u)(rex.lnum + rex.reg_firstlnum),
+									scan))
+		status = RA_NOMATCH;
+	    break;
+
+	  case RE_COL:
+	    if (!re_num_cmp((long_u)(rex.input - rex.line) + 1, scan))
+		status = RA_NOMATCH;
+	    break;
+
+	  case RE_VCOL:
+	    if (!re_num_cmp((long_u)win_linetabsize(
+			    rex.reg_win == NULL ? curwin : rex.reg_win,
+			    rex.line, (colnr_T)(rex.input - rex.line)) + 1, scan))
+		status = RA_NOMATCH;
+	    break;
+
+	  case BOW:	/* \<word; rex.input points to w */
+	    if (c == NUL)	/* Can't match at end of line */
+		status = RA_NOMATCH;
+	    else if (has_mbyte)
+	    {
+		int this_class;
+
+		/* Get class of current and previous char (if it exists). */
+		this_class = mb_get_class_buf(rex.input, rex.reg_buf);
+		if (this_class <= 1)
+		    status = RA_NOMATCH;  /* not on a word at all */
+		else if (reg_prev_class() == this_class)
+		    status = RA_NOMATCH;  /* previous char is in same word */
+	    }
+	    else
+	    {
+		if (!vim_iswordc_buf(c, rex.reg_buf) || (rex.input > rex.line
+				&& vim_iswordc_buf(rex.input[-1], rex.reg_buf)))
+		    status = RA_NOMATCH;
+	    }
+	    break;
+
+	  case EOW:	/* word\>; rex.input points after d */
+	    if (rex.input == rex.line)    /* Can't match at start of line */
+		status = RA_NOMATCH;
+	    else if (has_mbyte)
+	    {
+		int this_class, prev_class;
+
+		/* Get class of current and previous char (if it exists). */
+		this_class = mb_get_class_buf(rex.input, rex.reg_buf);
+		prev_class = reg_prev_class();
+		if (this_class == prev_class
+			|| prev_class == 0 || prev_class == 1)
+		    status = RA_NOMATCH;
+	    }
+	    else
+	    {
+		if (!vim_iswordc_buf(rex.input[-1], rex.reg_buf)
+			|| (rex.input[0] != NUL
+					   && vim_iswordc_buf(c, rex.reg_buf)))
+		    status = RA_NOMATCH;
+	    }
+	    break; /* Matched with EOW */
+
+	  case ANY:
+	    /* ANY does not match new lines. */
+	    if (c == NUL)
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case IDENT:
+	    if (!vim_isIDc(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case SIDENT:
+	    if (VIM_ISDIGIT(*rex.input) || !vim_isIDc(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case KWORD:
+	    if (!vim_iswordp_buf(rex.input, rex.reg_buf))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case SKWORD:
+	    if (VIM_ISDIGIT(*rex.input)
+				    || !vim_iswordp_buf(rex.input, rex.reg_buf))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case FNAME:
+	    if (!vim_isfilec(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case SFNAME:
+	    if (VIM_ISDIGIT(*rex.input) || !vim_isfilec(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case PRINT:
+	    if (!vim_isprintc(PTR2CHAR(rex.input)))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case SPRINT:
+	    if (VIM_ISDIGIT(*rex.input) || !vim_isprintc(PTR2CHAR(rex.input)))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case WHITE:
+	    if (!VIM_ISWHITE(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case NWHITE:
+	    if (c == NUL || VIM_ISWHITE(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case DIGIT:
+	    if (!ri_digit(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case NDIGIT:
+	    if (c == NUL || ri_digit(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case HEX:
+	    if (!ri_hex(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case NHEX:
+	    if (c == NUL || ri_hex(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case OCTAL:
+	    if (!ri_octal(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case NOCTAL:
+	    if (c == NUL || ri_octal(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case WORD:
+	    if (!ri_word(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case NWORD:
+	    if (c == NUL || ri_word(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case HEAD:
+	    if (!ri_head(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case NHEAD:
+	    if (c == NUL || ri_head(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case ALPHA:
+	    if (!ri_alpha(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case NALPHA:
+	    if (c == NUL || ri_alpha(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case LOWER:
+	    if (!ri_lower(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case NLOWER:
+	    if (c == NUL || ri_lower(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case UPPER:
+	    if (!ri_upper(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case NUPPER:
+	    if (c == NUL || ri_upper(c))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case EXACTLY:
+	    {
+		int	len;
+		char_u	*opnd;
+
+		opnd = OPERAND(scan);
+		/* Inline the first byte, for speed. */
+		if (*opnd != *rex.input
+			&& (!rex.reg_ic
+			    || (!enc_utf8
+			      && MB_TOLOWER(*opnd) != MB_TOLOWER(*rex.input))))
+		    status = RA_NOMATCH;
+		else if (*opnd == NUL)
+		{
+		    /* match empty string always works; happens when "~" is
+		     * empty. */
+		}
+		else
+		{
+		    if (opnd[1] == NUL && !(enc_utf8 && rex.reg_ic))
+		    {
+			len = 1;	/* matched a single byte above */
+		    }
+		    else
+		    {
+			/* Need to match first byte again for multi-byte. */
+			len = (int)STRLEN(opnd);
+			if (cstrncmp(opnd, rex.input, &len) != 0)
+			    status = RA_NOMATCH;
+		    }
+		    /* Check for following composing character, unless %C
+		     * follows (skips over all composing chars). */
+		    if (status != RA_NOMATCH
+			    && enc_utf8
+			    && UTF_COMPOSINGLIKE(rex.input, rex.input + len)
+			    && !rex.reg_icombine
+			    && OP(next) != RE_COMPOSING)
+		    {
+			/* raaron: This code makes a composing character get
+			 * ignored, which is the correct behavior (sometimes)
+			 * for voweled Hebrew texts. */
+			status = RA_NOMATCH;
+		    }
+		    if (status != RA_NOMATCH)
+			rex.input += len;
+		}
+	    }
+	    break;
+
+	  case ANYOF:
+	  case ANYBUT:
+	    if (c == NUL)
+		status = RA_NOMATCH;
+	    else if ((cstrchr(OPERAND(scan), c) == NULL) == (op == ANYOF))
+		status = RA_NOMATCH;
+	    else
+		ADVANCE_REGINPUT();
+	    break;
+
+	  case MULTIBYTECODE:
+	    if (has_mbyte)
+	    {
+		int	i, len;
+		char_u	*opnd;
+		int	opndc = 0, inpc;
+
+		opnd = OPERAND(scan);
+		/* Safety check (just in case 'encoding' was changed since
+		 * compiling the program). */
+		if ((len = (*mb_ptr2len)(opnd)) < 2)
+		{
+		    status = RA_NOMATCH;
+		    break;
+		}
+		if (enc_utf8)
+		    opndc = utf_ptr2char(opnd);
+		if (enc_utf8 && utf_iscomposing(opndc))
+		{
+		    /* When only a composing char is given match at any
+		     * position where that composing char appears. */
+		    status = RA_NOMATCH;
+		    for (i = 0; rex.input[i] != NUL;
+						i += utf_ptr2len(rex.input + i))
+		    {
+			inpc = utf_ptr2char(rex.input + i);
+			if (!utf_iscomposing(inpc))
+			{
+			    if (i > 0)
+				break;
+			}
+			else if (opndc == inpc)
+			{
+			    /* Include all following composing chars. */
+			    len = i + utfc_ptr2len(rex.input + i);
+			    status = RA_MATCH;
+			    break;
+			}
+		    }
+		}
+		else
+		    for (i = 0; i < len; ++i)
+			if (opnd[i] != rex.input[i])
+			{
+			    status = RA_NOMATCH;
+			    break;
+			}
+		rex.input += len;
+	    }
+	    else
+		status = RA_NOMATCH;
+	    break;
+	  case RE_COMPOSING:
+	    if (enc_utf8)
+	    {
+		/* Skip composing characters. */
+		while (utf_iscomposing(utf_ptr2char(rex.input)))
+		    MB_CPTR_ADV(rex.input);
+	    }
+	    break;
+
+	  case NOTHING:
+	    break;
+
+	  case BACK:
+	    {
+		int		i;
+		backpos_T	*bp;
+
+		/*
+		 * When we run into BACK we need to check if we don't keep
+		 * looping without matching any input.  The second and later
+		 * times a BACK is encountered it fails if the input is still
+		 * at the same position as the previous time.
+		 * The positions are stored in "backpos" and found by the
+		 * current value of "scan", the position in the RE program.
+		 */
+		bp = (backpos_T *)backpos.ga_data;
+		for (i = 0; i < backpos.ga_len; ++i)
+		    if (bp[i].bp_scan == scan)
+			break;
+		if (i == backpos.ga_len)
+		{
+		    /* First time at this BACK, make room to store the pos. */
+		    if (ga_grow(&backpos, 1) == FAIL)
+			status = RA_FAIL;
+		    else
+		    {
+			/* get "ga_data" again, it may have changed */
+			bp = (backpos_T *)backpos.ga_data;
+			bp[i].bp_scan = scan;
+			++backpos.ga_len;
+		    }
+		}
+		else if (reg_save_equal(&bp[i].bp_pos))
+		    /* Still at same position as last time, fail. */
+		    status = RA_NOMATCH;
+
+		if (status != RA_FAIL && status != RA_NOMATCH)
+		    reg_save(&bp[i].bp_pos, &backpos);
+	    }
+	    break;
+
+	  case MOPEN + 0:   /* Match start: \zs */
+	  case MOPEN + 1:   /* \( */
+	  case MOPEN + 2:
+	  case MOPEN + 3:
+	  case MOPEN + 4:
+	  case MOPEN + 5:
+	  case MOPEN + 6:
+	  case MOPEN + 7:
+	  case MOPEN + 8:
+	  case MOPEN + 9:
+	    {
+		no = op - MOPEN;
+		cleanup_subexpr();
+		rp = regstack_push(RS_MOPEN, scan);
+		if (rp == NULL)
+		    status = RA_FAIL;
+		else
+		{
+		    rp->rs_no = no;
+		    save_se(&rp->rs_un.sesave, &rex.reg_startpos[no],
+							  &rex.reg_startp[no]);
+		    /* We simply continue and handle the result when done. */
+		}
+	    }
+	    break;
+
+	  case NOPEN:	    /* \%( */
+	  case NCLOSE:	    /* \) after \%( */
+		if (regstack_push(RS_NOPEN, scan) == NULL)
+		    status = RA_FAIL;
+		/* We simply continue and handle the result when done. */
+		break;
+
+#ifdef FEAT_SYN_HL
+	  case ZOPEN + 1:
+	  case ZOPEN + 2:
+	  case ZOPEN + 3:
+	  case ZOPEN + 4:
+	  case ZOPEN + 5:
+	  case ZOPEN + 6:
+	  case ZOPEN + 7:
+	  case ZOPEN + 8:
+	  case ZOPEN + 9:
+	    {
+		no = op - ZOPEN;
+		cleanup_zsubexpr();
+		rp = regstack_push(RS_ZOPEN, scan);
+		if (rp == NULL)
+		    status = RA_FAIL;
+		else
+		{
+		    rp->rs_no = no;
+		    save_se(&rp->rs_un.sesave, &reg_startzpos[no],
+							     &reg_startzp[no]);
+		    /* We simply continue and handle the result when done. */
+		}
+	    }
+	    break;
+#endif
+
+	  case MCLOSE + 0:  /* Match end: \ze */
+	  case MCLOSE + 1:  /* \) */
+	  case MCLOSE + 2:
+	  case MCLOSE + 3:
+	  case MCLOSE + 4:
+	  case MCLOSE + 5:
+	  case MCLOSE + 6:
+	  case MCLOSE + 7:
+	  case MCLOSE + 8:
+	  case MCLOSE + 9:
+	    {
+		no = op - MCLOSE;
+		cleanup_subexpr();
+		rp = regstack_push(RS_MCLOSE, scan);
+		if (rp == NULL)
+		    status = RA_FAIL;
+		else
+		{
+		    rp->rs_no = no;
+		    save_se(&rp->rs_un.sesave, &rex.reg_endpos[no],
+							    &rex.reg_endp[no]);
+		    /* We simply continue and handle the result when done. */
+		}
+	    }
+	    break;
+
+#ifdef FEAT_SYN_HL
+	  case ZCLOSE + 1:  /* \) after \z( */
+	  case ZCLOSE + 2:
+	  case ZCLOSE + 3:
+	  case ZCLOSE + 4:
+	  case ZCLOSE + 5:
+	  case ZCLOSE + 6:
+	  case ZCLOSE + 7:
+	  case ZCLOSE + 8:
+	  case ZCLOSE + 9:
+	    {
+		no = op - ZCLOSE;
+		cleanup_zsubexpr();
+		rp = regstack_push(RS_ZCLOSE, scan);
+		if (rp == NULL)
+		    status = RA_FAIL;
+		else
+		{
+		    rp->rs_no = no;
+		    save_se(&rp->rs_un.sesave, &reg_endzpos[no],
+							      &reg_endzp[no]);
+		    /* We simply continue and handle the result when done. */
+		}
+	    }
+	    break;
+#endif
+
+	  case BACKREF + 1:
+	  case BACKREF + 2:
+	  case BACKREF + 3:
+	  case BACKREF + 4:
+	  case BACKREF + 5:
+	  case BACKREF + 6:
+	  case BACKREF + 7:
+	  case BACKREF + 8:
+	  case BACKREF + 9:
+	    {
+		int		len;
+
+		no = op - BACKREF;
+		cleanup_subexpr();
+		if (!REG_MULTI)		/* Single-line regexp */
+		{
+		    if (rex.reg_startp[no] == NULL || rex.reg_endp[no] == NULL)
+		    {
+			/* Backref was not set: Match an empty string. */
+			len = 0;
+		    }
+		    else
+		    {
+			/* Compare current input with back-ref in the same
+			 * line. */
+			len = (int)(rex.reg_endp[no] - rex.reg_startp[no]);
+			if (cstrncmp(rex.reg_startp[no], rex.input, &len) != 0)
+			    status = RA_NOMATCH;
+		    }
+		}
+		else				/* Multi-line regexp */
+		{
+		    if (rex.reg_startpos[no].lnum < 0
+						|| rex.reg_endpos[no].lnum < 0)
+		    {
+			/* Backref was not set: Match an empty string. */
+			len = 0;
+		    }
+		    else
+		    {
+			if (rex.reg_startpos[no].lnum == rex.lnum
+				&& rex.reg_endpos[no].lnum == rex.lnum)
+			{
+			    /* Compare back-ref within the current line. */
+			    len = rex.reg_endpos[no].col
+						    - rex.reg_startpos[no].col;
+			    if (cstrncmp(rex.line + rex.reg_startpos[no].col,
+							  rex.input, &len) != 0)
+				status = RA_NOMATCH;
+			}
+			else
+			{
+			    /* Messy situation: Need to compare between two
+			     * lines. */
+			    int r = match_with_backref(
+					    rex.reg_startpos[no].lnum,
+					    rex.reg_startpos[no].col,
+					    rex.reg_endpos[no].lnum,
+					    rex.reg_endpos[no].col,
+					    &len);
+
+			    if (r != RA_MATCH)
+				status = r;
+			}
+		    }
+		}
+
+		/* Matched the backref, skip over it. */
+		rex.input += len;
+	    }
+	    break;
+
+#ifdef FEAT_SYN_HL
+	  case ZREF + 1:
+	  case ZREF + 2:
+	  case ZREF + 3:
+	  case ZREF + 4:
+	  case ZREF + 5:
+	  case ZREF + 6:
+	  case ZREF + 7:
+	  case ZREF + 8:
+	  case ZREF + 9:
+	    {
+		int	len;
+
+		cleanup_zsubexpr();
+		no = op - ZREF;
+		if (re_extmatch_in != NULL
+			&& re_extmatch_in->matches[no] != NULL)
+		{
+		    len = (int)STRLEN(re_extmatch_in->matches[no]);
+		    if (cstrncmp(re_extmatch_in->matches[no],
+							  rex.input, &len) != 0)
+			status = RA_NOMATCH;
+		    else
+			rex.input += len;
+		}
+		else
+		{
+		    /* Backref was not set: Match an empty string. */
+		}
+	    }
+	    break;
+#endif
+
+	  case BRANCH:
+	    {
+		if (OP(next) != BRANCH) /* No choice. */
+		    next = OPERAND(scan);	/* Avoid recursion. */
+		else
+		{
+		    rp = regstack_push(RS_BRANCH, scan);
+		    if (rp == NULL)
+			status = RA_FAIL;
+		    else
+			status = RA_BREAK;	/* rest is below */
+		}
+	    }
+	    break;
+
+	  case BRACE_LIMITS:
+	    {
+		if (OP(next) == BRACE_SIMPLE)
+		{
+		    bl_minval = OPERAND_MIN(scan);
+		    bl_maxval = OPERAND_MAX(scan);
+		}
+		else if (OP(next) >= BRACE_COMPLEX
+			&& OP(next) < BRACE_COMPLEX + 10)
+		{
+		    no = OP(next) - BRACE_COMPLEX;
+		    brace_min[no] = OPERAND_MIN(scan);
+		    brace_max[no] = OPERAND_MAX(scan);
+		    brace_count[no] = 0;
+		}
+		else
+		{
+		    internal_error("BRACE_LIMITS");
+		    status = RA_FAIL;
+		}
+	    }
+	    break;
+
+	  case BRACE_COMPLEX + 0:
+	  case BRACE_COMPLEX + 1:
+	  case BRACE_COMPLEX + 2:
+	  case BRACE_COMPLEX + 3:
+	  case BRACE_COMPLEX + 4:
+	  case BRACE_COMPLEX + 5:
+	  case BRACE_COMPLEX + 6:
+	  case BRACE_COMPLEX + 7:
+	  case BRACE_COMPLEX + 8:
+	  case BRACE_COMPLEX + 9:
+	    {
+		no = op - BRACE_COMPLEX;
+		++brace_count[no];
+
+		/* If not matched enough times yet, try one more */
+		if (brace_count[no] <= (brace_min[no] <= brace_max[no]
+					     ? brace_min[no] : brace_max[no]))
+		{
+		    rp = regstack_push(RS_BRCPLX_MORE, scan);
+		    if (rp == NULL)
+			status = RA_FAIL;
+		    else
+		    {
+			rp->rs_no = no;
+			reg_save(&rp->rs_un.regsave, &backpos);
+			next = OPERAND(scan);
+			/* We continue and handle the result when done. */
+		    }
+		    break;
+		}
+
+		/* If matched enough times, may try matching some more */
+		if (brace_min[no] <= brace_max[no])
+		{
+		    /* Range is the normal way around, use longest match */
+		    if (brace_count[no] <= brace_max[no])
+		    {
+			rp = regstack_push(RS_BRCPLX_LONG, scan);
+			if (rp == NULL)
+			    status = RA_FAIL;
+			else
+			{
+			    rp->rs_no = no;
+			    reg_save(&rp->rs_un.regsave, &backpos);
+			    next = OPERAND(scan);
+			    /* We continue and handle the result when done. */
+			}
+		    }
+		}
+		else
+		{
+		    /* Range is backwards, use shortest match first */
+		    if (brace_count[no] <= brace_min[no])
+		    {
+			rp = regstack_push(RS_BRCPLX_SHORT, scan);
+			if (rp == NULL)
+			    status = RA_FAIL;
+			else
+			{
+			    reg_save(&rp->rs_un.regsave, &backpos);
+			    /* We continue and handle the result when done. */
+			}
+		    }
+		}
+	    }
+	    break;
+
+	  case BRACE_SIMPLE:
+	  case STAR:
+	  case PLUS:
+	    {
+		regstar_T	rst;
+
+		/*
+		 * Lookahead to avoid useless match attempts when we know
+		 * what character comes next.
+		 */
+		if (OP(next) == EXACTLY)
+		{
+		    rst.nextb = *OPERAND(next);
+		    if (rex.reg_ic)
+		    {
+			if (MB_ISUPPER(rst.nextb))
+			    rst.nextb_ic = MB_TOLOWER(rst.nextb);
+			else
+			    rst.nextb_ic = MB_TOUPPER(rst.nextb);
+		    }
+		    else
+			rst.nextb_ic = rst.nextb;
+		}
+		else
+		{
+		    rst.nextb = NUL;
+		    rst.nextb_ic = NUL;
+		}
+		if (op != BRACE_SIMPLE)
+		{
+		    rst.minval = (op == STAR) ? 0 : 1;
+		    rst.maxval = MAX_LIMIT;
+		}
+		else
+		{
+		    rst.minval = bl_minval;
+		    rst.maxval = bl_maxval;
+		}
+
+		/*
+		 * When maxval > minval, try matching as much as possible, up
+		 * to maxval.  When maxval < minval, try matching at least the
+		 * minimal number (since the range is backwards, that's also
+		 * maxval!).
+		 */
+		rst.count = regrepeat(OPERAND(scan), rst.maxval);
+		if (got_int)
+		{
+		    status = RA_FAIL;
+		    break;
+		}
+		if (rst.minval <= rst.maxval
+			  ? rst.count >= rst.minval : rst.count >= rst.maxval)
+		{
+		    /* It could match.  Prepare for trying to match what
+		     * follows.  The code is below.  Parameters are stored in
+		     * a regstar_T on the regstack. */
+		    if ((long)((unsigned)regstack.ga_len >> 10) >= p_mmp)
+		    {
+			emsg(_(e_maxmempat));
+			status = RA_FAIL;
+		    }
+		    else if (ga_grow(&regstack, sizeof(regstar_T)) == FAIL)
+			status = RA_FAIL;
+		    else
+		    {
+			regstack.ga_len += sizeof(regstar_T);
+			rp = regstack_push(rst.minval <= rst.maxval
+					? RS_STAR_LONG : RS_STAR_SHORT, scan);
+			if (rp == NULL)
+			    status = RA_FAIL;
+			else
+			{
+			    *(((regstar_T *)rp) - 1) = rst;
+			    status = RA_BREAK;	    /* skip the restore bits */
+			}
+		    }
+		}
+		else
+		    status = RA_NOMATCH;
+
+	    }
+	    break;
+
+	  case NOMATCH:
+	  case MATCH:
+	  case SUBPAT:
+	    rp = regstack_push(RS_NOMATCH, scan);
+	    if (rp == NULL)
+		status = RA_FAIL;
+	    else
+	    {
+		rp->rs_no = op;
+		reg_save(&rp->rs_un.regsave, &backpos);
+		next = OPERAND(scan);
+		/* We continue and handle the result when done. */
+	    }
+	    break;
+
+	  case BEHIND:
+	  case NOBEHIND:
+	    /* Need a bit of room to store extra positions. */
+	    if ((long)((unsigned)regstack.ga_len >> 10) >= p_mmp)
+	    {
+		emsg(_(e_maxmempat));
+		status = RA_FAIL;
+	    }
+	    else if (ga_grow(&regstack, sizeof(regbehind_T)) == FAIL)
+		status = RA_FAIL;
+	    else
+	    {
+		regstack.ga_len += sizeof(regbehind_T);
+		rp = regstack_push(RS_BEHIND1, scan);
+		if (rp == NULL)
+		    status = RA_FAIL;
+		else
+		{
+		    /* Need to save the subexpr to be able to restore them
+		     * when there is a match but we don't use it. */
+		    save_subexpr(((regbehind_T *)rp) - 1);
+
+		    rp->rs_no = op;
+		    reg_save(&rp->rs_un.regsave, &backpos);
+		    /* First try if what follows matches.  If it does then we
+		     * check the behind match by looping. */
+		}
+	    }
+	    break;
+
+	  case BHPOS:
+	    if (REG_MULTI)
+	    {
+		if (behind_pos.rs_u.pos.col != (colnr_T)(rex.input - rex.line)
+			|| behind_pos.rs_u.pos.lnum != rex.lnum)
+		    status = RA_NOMATCH;
+	    }
+	    else if (behind_pos.rs_u.ptr != rex.input)
+		status = RA_NOMATCH;
+	    break;
+
+	  case NEWL:
+	    if ((c != NUL || !REG_MULTI || rex.lnum > rex.reg_maxline
+			     || rex.reg_line_lbr)
+					   && (c != '\n' || !rex.reg_line_lbr))
+		status = RA_NOMATCH;
+	    else if (rex.reg_line_lbr)
+		ADVANCE_REGINPUT();
+	    else
+		reg_nextline();
+	    break;
+
+	  case END:
+	    status = RA_MATCH;	/* Success! */
+	    break;
+
+	  default:
+	    emsg(_(e_re_corr));
+#ifdef DEBUG
+	    printf("Illegal op code %d\n", op);
+#endif
+	    status = RA_FAIL;
+	    break;
+	  }
+	}
+
+	/* If we can't continue sequentially, break the inner loop. */
+	if (status != RA_CONT)
+	    break;
+
+	/* Continue in inner loop, advance to next item. */
+	scan = next;
+
+    } /* end of inner loop */
+
+    /*
+     * If there is something on the regstack execute the code for the state.
+     * If the state is popped then loop and use the older state.
+     */
+    while (regstack.ga_len > 0 && status != RA_FAIL)
+    {
+	rp = (regitem_T *)((char *)regstack.ga_data + regstack.ga_len) - 1;
+	switch (rp->rs_state)
+	{
+	  case RS_NOPEN:
+	    /* Result is passed on as-is, simply pop the state. */
+	    regstack_pop(&scan);
+	    break;
+
+	  case RS_MOPEN:
+	    /* Pop the state.  Restore pointers when there is no match. */
+	    if (status == RA_NOMATCH)
+		restore_se(&rp->rs_un.sesave, &rex.reg_startpos[rp->rs_no],
+						  &rex.reg_startp[rp->rs_no]);
+	    regstack_pop(&scan);
+	    break;
+
+#ifdef FEAT_SYN_HL
+	  case RS_ZOPEN:
+	    /* Pop the state.  Restore pointers when there is no match. */
+	    if (status == RA_NOMATCH)
+		restore_se(&rp->rs_un.sesave, &reg_startzpos[rp->rs_no],
+						 &reg_startzp[rp->rs_no]);
+	    regstack_pop(&scan);
+	    break;
+#endif
+
+	  case RS_MCLOSE:
+	    /* Pop the state.  Restore pointers when there is no match. */
+	    if (status == RA_NOMATCH)
+		restore_se(&rp->rs_un.sesave, &rex.reg_endpos[rp->rs_no],
+						    &rex.reg_endp[rp->rs_no]);
+	    regstack_pop(&scan);
+	    break;
+
+#ifdef FEAT_SYN_HL
+	  case RS_ZCLOSE:
+	    /* Pop the state.  Restore pointers when there is no match. */
+	    if (status == RA_NOMATCH)
+		restore_se(&rp->rs_un.sesave, &reg_endzpos[rp->rs_no],
+						   &reg_endzp[rp->rs_no]);
+	    regstack_pop(&scan);
+	    break;
+#endif
+
+	  case RS_BRANCH:
+	    if (status == RA_MATCH)
+		/* this branch matched, use it */
+		regstack_pop(&scan);
+	    else
+	    {
+		if (status != RA_BREAK)
+		{
+		    /* After a non-matching branch: try next one. */
+		    reg_restore(&rp->rs_un.regsave, &backpos);
+		    scan = rp->rs_scan;
+		}
+		if (scan == NULL || OP(scan) != BRANCH)
+		{
+		    /* no more branches, didn't find a match */
+		    status = RA_NOMATCH;
+		    regstack_pop(&scan);
+		}
+		else
+		{
+		    /* Prepare to try a branch. */
+		    rp->rs_scan = regnext(scan);
+		    reg_save(&rp->rs_un.regsave, &backpos);
+		    scan = OPERAND(scan);
+		}
+	    }
+	    break;
+
+	  case RS_BRCPLX_MORE:
+	    /* Pop the state.  Restore pointers when there is no match. */
+	    if (status == RA_NOMATCH)
+	    {
+		reg_restore(&rp->rs_un.regsave, &backpos);
+		--brace_count[rp->rs_no];	/* decrement match count */
+	    }
+	    regstack_pop(&scan);
+	    break;
+
+	  case RS_BRCPLX_LONG:
+	    /* Pop the state.  Restore pointers when there is no match. */
+	    if (status == RA_NOMATCH)
+	    {
+		/* There was no match, but we did find enough matches. */
+		reg_restore(&rp->rs_un.regsave, &backpos);
+		--brace_count[rp->rs_no];
+		/* continue with the items after "\{}" */
+		status = RA_CONT;
+	    }
+	    regstack_pop(&scan);
+	    if (status == RA_CONT)
+		scan = regnext(scan);
+	    break;
+
+	  case RS_BRCPLX_SHORT:
+	    /* Pop the state.  Restore pointers when there is no match. */
+	    if (status == RA_NOMATCH)
+		/* There was no match, try to match one more item. */
+		reg_restore(&rp->rs_un.regsave, &backpos);
+	    regstack_pop(&scan);
+	    if (status == RA_NOMATCH)
+	    {
+		scan = OPERAND(scan);
+		status = RA_CONT;
+	    }
+	    break;
+
+	  case RS_NOMATCH:
+	    /* Pop the state.  If the operand matches for NOMATCH or
+	     * doesn't match for MATCH/SUBPAT, we fail.  Otherwise backup,
+	     * except for SUBPAT, and continue with the next item. */
+	    if (status == (rp->rs_no == NOMATCH ? RA_MATCH : RA_NOMATCH))
+		status = RA_NOMATCH;
+	    else
+	    {
+		status = RA_CONT;
+		if (rp->rs_no != SUBPAT)	/* zero-width */
+		    reg_restore(&rp->rs_un.regsave, &backpos);
+	    }
+	    regstack_pop(&scan);
+	    if (status == RA_CONT)
+		scan = regnext(scan);
+	    break;
+
+	  case RS_BEHIND1:
+	    if (status == RA_NOMATCH)
+	    {
+		regstack_pop(&scan);
+		regstack.ga_len -= sizeof(regbehind_T);
+	    }
+	    else
+	    {
+		/* The stuff after BEHIND/NOBEHIND matches.  Now try if
+		 * the behind part does (not) match before the current
+		 * position in the input.  This must be done at every
+		 * position in the input and checking if the match ends at
+		 * the current position. */
+
+		/* save the position after the found match for next */
+		reg_save(&(((regbehind_T *)rp) - 1)->save_after, &backpos);
+
+		/* Start looking for a match with operand at the current
+		 * position.  Go back one character until we find the
+		 * result, hitting the start of the line or the previous
+		 * line (for multi-line matching).
+		 * Set behind_pos to where the match should end, BHPOS
+		 * will match it.  Save the current value. */
+		(((regbehind_T *)rp) - 1)->save_behind = behind_pos;
+		behind_pos = rp->rs_un.regsave;
+
+		rp->rs_state = RS_BEHIND2;
+
+		reg_restore(&rp->rs_un.regsave, &backpos);
+		scan = OPERAND(rp->rs_scan) + 4;
+	    }
+	    break;
+
+	  case RS_BEHIND2:
+	    /*
+	     * Looping for BEHIND / NOBEHIND match.
+	     */
+	    if (status == RA_MATCH && reg_save_equal(&behind_pos))
+	    {
+		/* found a match that ends where "next" started */
+		behind_pos = (((regbehind_T *)rp) - 1)->save_behind;
+		if (rp->rs_no == BEHIND)
+		    reg_restore(&(((regbehind_T *)rp) - 1)->save_after,
+								    &backpos);
+		else
+		{
+		    /* But we didn't want a match.  Need to restore the
+		     * subexpr, because what follows matched, so they have
+		     * been set. */
+		    status = RA_NOMATCH;
+		    restore_subexpr(((regbehind_T *)rp) - 1);
+		}
+		regstack_pop(&scan);
+		regstack.ga_len -= sizeof(regbehind_T);
+	    }
+	    else
+	    {
+		long limit;
+
+		/* No match or a match that doesn't end where we want it: Go
+		 * back one character.  May go to previous line once. */
+		no = OK;
+		limit = OPERAND_MIN(rp->rs_scan);
+		if (REG_MULTI)
+		{
+		    if (limit > 0
+			    && ((rp->rs_un.regsave.rs_u.pos.lnum
+						    < behind_pos.rs_u.pos.lnum
+				    ? (colnr_T)STRLEN(rex.line)
+				    : behind_pos.rs_u.pos.col)
+				- rp->rs_un.regsave.rs_u.pos.col >= limit))
+			no = FAIL;
+		    else if (rp->rs_un.regsave.rs_u.pos.col == 0)
+		    {
+			if (rp->rs_un.regsave.rs_u.pos.lnum
+					< behind_pos.rs_u.pos.lnum
+				|| reg_getline(
+					--rp->rs_un.regsave.rs_u.pos.lnum)
+								  == NULL)
+			    no = FAIL;
+			else
+			{
+			    reg_restore(&rp->rs_un.regsave, &backpos);
+			    rp->rs_un.regsave.rs_u.pos.col =
+						 (colnr_T)STRLEN(rex.line);
+			}
+		    }
+		    else
+		    {
+			if (has_mbyte)
+			{
+			    char_u *line =
+				  reg_getline(rp->rs_un.regsave.rs_u.pos.lnum);
+
+			    rp->rs_un.regsave.rs_u.pos.col -=
+				(*mb_head_off)(line, line
+				    + rp->rs_un.regsave.rs_u.pos.col - 1) + 1;
+			}
+			else
+			    --rp->rs_un.regsave.rs_u.pos.col;
+		    }
+		}
+		else
+		{
+		    if (rp->rs_un.regsave.rs_u.ptr == rex.line)
+			no = FAIL;
+		    else
+		    {
+			MB_PTR_BACK(rex.line, rp->rs_un.regsave.rs_u.ptr);
+			if (limit > 0 && (long)(behind_pos.rs_u.ptr
+				     - rp->rs_un.regsave.rs_u.ptr) > limit)
+			    no = FAIL;
+		    }
+		}
+		if (no == OK)
+		{
+		    /* Advanced, prepare for finding match again. */
+		    reg_restore(&rp->rs_un.regsave, &backpos);
+		    scan = OPERAND(rp->rs_scan) + 4;
+		    if (status == RA_MATCH)
+		    {
+			/* We did match, so subexpr may have been changed,
+			 * need to restore them for the next try. */
+			status = RA_NOMATCH;
+			restore_subexpr(((regbehind_T *)rp) - 1);
+		    }
+		}
+		else
+		{
+		    /* Can't advance.  For NOBEHIND that's a match. */
+		    behind_pos = (((regbehind_T *)rp) - 1)->save_behind;
+		    if (rp->rs_no == NOBEHIND)
+		    {
+			reg_restore(&(((regbehind_T *)rp) - 1)->save_after,
+								    &backpos);
+			status = RA_MATCH;
+		    }
+		    else
+		    {
+			/* We do want a proper match.  Need to restore the
+			 * subexpr if we had a match, because they may have
+			 * been set. */
+			if (status == RA_MATCH)
+			{
+			    status = RA_NOMATCH;
+			    restore_subexpr(((regbehind_T *)rp) - 1);
+			}
+		    }
+		    regstack_pop(&scan);
+		    regstack.ga_len -= sizeof(regbehind_T);
+		}
+	    }
+	    break;
+
+	  case RS_STAR_LONG:
+	  case RS_STAR_SHORT:
+	    {
+		regstar_T	    *rst = ((regstar_T *)rp) - 1;
+
+		if (status == RA_MATCH)
+		{
+		    regstack_pop(&scan);
+		    regstack.ga_len -= sizeof(regstar_T);
+		    break;
+		}
+
+		/* Tried once already, restore input pointers. */
+		if (status != RA_BREAK)
+		    reg_restore(&rp->rs_un.regsave, &backpos);
+
+		/* Repeat until we found a position where it could match. */
+		for (;;)
+		{
+		    if (status != RA_BREAK)
+		    {
+			/* Tried first position already, advance. */
+			if (rp->rs_state == RS_STAR_LONG)
+			{
+			    /* Trying for longest match, but couldn't or
+			     * didn't match -- back up one char. */
+			    if (--rst->count < rst->minval)
+				break;
+			    if (rex.input == rex.line)
+			    {
+				/* backup to last char of previous line */
+				--rex.lnum;
+				rex.line = reg_getline(rex.lnum);
+				/* Just in case regrepeat() didn't count
+				 * right. */
+				if (rex.line == NULL)
+				    break;
+				rex.input = rex.line + STRLEN(rex.line);
+				fast_breakcheck();
+			    }
+			    else
+				MB_PTR_BACK(rex.line, rex.input);
+			}
+			else
+			{
+			    /* Range is backwards, use shortest match first.
+			     * Careful: maxval and minval are exchanged!
+			     * Couldn't or didn't match: try advancing one
+			     * char. */
+			    if (rst->count == rst->minval
+				  || regrepeat(OPERAND(rp->rs_scan), 1L) == 0)
+				break;
+			    ++rst->count;
+			}
+			if (got_int)
+			    break;
+		    }
+		    else
+			status = RA_NOMATCH;
+
+		    /* If it could match, try it. */
+		    if (rst->nextb == NUL || *rex.input == rst->nextb
+					     || *rex.input == rst->nextb_ic)
+		    {
+			reg_save(&rp->rs_un.regsave, &backpos);
+			scan = regnext(rp->rs_scan);
+			status = RA_CONT;
+			break;
+		    }
+		}
+		if (status != RA_CONT)
+		{
+		    /* Failed. */
+		    regstack_pop(&scan);
+		    regstack.ga_len -= sizeof(regstar_T);
+		    status = RA_NOMATCH;
+		}
+	    }
+	    break;
+	}
+
+	/* If we want to continue the inner loop or didn't pop a state
+	 * continue matching loop */
+	if (status == RA_CONT || rp == (regitem_T *)
+			     ((char *)regstack.ga_data + regstack.ga_len) - 1)
+	    break;
+    }
+
+    /* May need to continue with the inner loop, starting at "scan". */
+    if (status == RA_CONT)
+	continue;
+
+    /*
+     * If the regstack is empty or something failed we are done.
+     */
+    if (regstack.ga_len == 0 || status == RA_FAIL)
+    {
+	if (scan == NULL)
+	{
+	    /*
+	     * We get here only if there's trouble -- normally "case END" is
+	     * the terminating point.
+	     */
+	    emsg(_(e_re_corr));
+#ifdef DEBUG
+	    printf("Premature EOL\n");
+#endif
+	}
+	return (status == RA_MATCH);
+    }
+
+  } /* End of loop until the regstack is empty. */
+
+  /* NOTREACHED */
+}
+
+/*
+ * regtry - try match of "prog" with at rex.line["col"].
+ * Returns 0 for failure, number of lines contained in the match otherwise.
+ */
+    static long
+regtry(
+    bt_regprog_T	*prog,
+    colnr_T		col,
+    proftime_T		*tm,		// timeout limit or NULL
+    int			*timed_out)	// flag set on timeout or NULL
+{
+    rex.input = rex.line + col;
+    rex.need_clear_subexpr = TRUE;
+#ifdef FEAT_SYN_HL
+    // Clear the external match subpointers if necessary.
+    rex.need_clear_zsubexpr = (prog->reghasz == REX_SET);
+#endif
+
+    if (regmatch(prog->program + 1, tm, timed_out) == 0)
+	return 0;
+
+    cleanup_subexpr();
+    if (REG_MULTI)
+    {
+	if (rex.reg_startpos[0].lnum < 0)
+	{
+	    rex.reg_startpos[0].lnum = 0;
+	    rex.reg_startpos[0].col = col;
+	}
+	if (rex.reg_endpos[0].lnum < 0)
+	{
+	    rex.reg_endpos[0].lnum = rex.lnum;
+	    rex.reg_endpos[0].col = (int)(rex.input - rex.line);
+	}
+	else
+	    // Use line number of "\ze".
+	    rex.lnum = rex.reg_endpos[0].lnum;
+    }
+    else
+    {
+	if (rex.reg_startp[0] == NULL)
+	    rex.reg_startp[0] = rex.line + col;
+	if (rex.reg_endp[0] == NULL)
+	    rex.reg_endp[0] = rex.input;
+    }
+#ifdef FEAT_SYN_HL
+    // Package any found \z(...\) matches for export. Default is none.
+    unref_extmatch(re_extmatch_out);
+    re_extmatch_out = NULL;
+
+    if (prog->reghasz == REX_SET)
+    {
+	int		i;
+
+	cleanup_zsubexpr();
+	re_extmatch_out = make_extmatch();
+	for (i = 0; i < NSUBEXP; i++)
+	{
+	    if (REG_MULTI)
+	    {
+		// Only accept single line matches.
+		if (reg_startzpos[i].lnum >= 0
+			&& reg_endzpos[i].lnum == reg_startzpos[i].lnum
+			&& reg_endzpos[i].col >= reg_startzpos[i].col)
+		    re_extmatch_out->matches[i] =
+			vim_strnsave(reg_getline(reg_startzpos[i].lnum)
+						       + reg_startzpos[i].col,
+				   reg_endzpos[i].col - reg_startzpos[i].col);
+	    }
+	    else
+	    {
+		if (reg_startzp[i] != NULL && reg_endzp[i] != NULL)
+		    re_extmatch_out->matches[i] =
+			    vim_strnsave(reg_startzp[i],
+					(int)(reg_endzp[i] - reg_startzp[i]));
+	    }
+	}
+    }
+#endif
+    return 1 + rex.lnum;
+}
+
+/*
+ * Match a regexp against a string ("line" points to the string) or multiple
+ * lines ("line" is NULL, use reg_getline()).
+ * Returns 0 for failure, number of lines contained in the match otherwise.
+ */
+    static long
+bt_regexec_both(
+    char_u	*line,
+    colnr_T	col,		// column to start looking for match
+    proftime_T	*tm,		// timeout limit or NULL
+    int		*timed_out)	// flag set on timeout or NULL
+{
+    bt_regprog_T    *prog;
+    char_u	    *s;
+    long	    retval = 0L;
+
+    // Create "regstack" and "backpos" if they are not allocated yet.
+    // We allocate *_INITIAL amount of bytes first and then set the grow size
+    // to much bigger value to avoid many malloc calls in case of deep regular
+    // expressions.
+    if (regstack.ga_data == NULL)
+    {
+	// Use an item size of 1 byte, since we push different things
+	// onto the regstack.
+	ga_init2(&regstack, 1, REGSTACK_INITIAL);
+	(void)ga_grow(&regstack, REGSTACK_INITIAL);
+	regstack.ga_growsize = REGSTACK_INITIAL * 8;
+    }
+
+    if (backpos.ga_data == NULL)
+    {
+	ga_init2(&backpos, sizeof(backpos_T), BACKPOS_INITIAL);
+	(void)ga_grow(&backpos, BACKPOS_INITIAL);
+	backpos.ga_growsize = BACKPOS_INITIAL * 8;
+    }
+
+    if (REG_MULTI)
+    {
+	prog = (bt_regprog_T *)rex.reg_mmatch->regprog;
+	line = reg_getline((linenr_T)0);
+	rex.reg_startpos = rex.reg_mmatch->startpos;
+	rex.reg_endpos = rex.reg_mmatch->endpos;
+    }
+    else
+    {
+	prog = (bt_regprog_T *)rex.reg_match->regprog;
+	rex.reg_startp = rex.reg_match->startp;
+	rex.reg_endp = rex.reg_match->endp;
+    }
+
+    // Be paranoid...
+    if (prog == NULL || line == NULL)
+    {
+	emsg(_(e_null));
+	goto theend;
+    }
+
+    // Check validity of program.
+    if (prog_magic_wrong())
+	goto theend;
+
+    // If the start column is past the maximum column: no need to try.
+    if (rex.reg_maxcol > 0 && col >= rex.reg_maxcol)
+	goto theend;
+
+    // If pattern contains "\c" or "\C": overrule value of rex.reg_ic
+    if (prog->regflags & RF_ICASE)
+	rex.reg_ic = TRUE;
+    else if (prog->regflags & RF_NOICASE)
+	rex.reg_ic = FALSE;
+
+    // If pattern contains "\Z" overrule value of rex.reg_icombine
+    if (prog->regflags & RF_ICOMBINE)
+	rex.reg_icombine = TRUE;
+
+    // If there is a "must appear" string, look for it.
+    if (prog->regmust != NULL)
+    {
+	int c;
+
+	if (has_mbyte)
+	    c = (*mb_ptr2char)(prog->regmust);
+	else
+	    c = *prog->regmust;
+	s = line + col;
+
+	// This is used very often, esp. for ":global".  Use three versions of
+	// the loop to avoid overhead of conditions.
+	if (!rex.reg_ic && !has_mbyte)
+	    while ((s = vim_strbyte(s, c)) != NULL)
+	    {
+		if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0)
+		    break;		// Found it.
+		++s;
+	    }
+	else if (!rex.reg_ic || (!enc_utf8 && mb_char2len(c) > 1))
+	    while ((s = vim_strchr(s, c)) != NULL)
+	    {
+		if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0)
+		    break;		// Found it.
+		MB_PTR_ADV(s);
+	    }
+	else
+	    while ((s = cstrchr(s, c)) != NULL)
+	    {
+		if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0)
+		    break;		// Found it.
+		MB_PTR_ADV(s);
+	    }
+	if (s == NULL)		// Not present.
+	    goto theend;
+    }
+
+    rex.line = line;
+    rex.lnum = 0;
+    reg_toolong = FALSE;
+
+    // Simplest case: Anchored match need be tried only once.
+    if (prog->reganch)
+    {
+	int	c;
+
+	if (has_mbyte)
+	    c = (*mb_ptr2char)(rex.line + col);
+	else
+	    c = rex.line[col];
+	if (prog->regstart == NUL
+		|| prog->regstart == c
+		|| (rex.reg_ic
+		    && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c)))
+			|| (c < 255 && prog->regstart < 255 &&
+			    MB_TOLOWER(prog->regstart) == MB_TOLOWER(c)))))
+	    retval = regtry(prog, col, tm, timed_out);
+	else
+	    retval = 0;
+    }
+    else
+    {
+#ifdef FEAT_RELTIME
+	int tm_count = 0;
+#endif
+	// Messy cases:  unanchored match.
+	while (!got_int)
+	{
+	    if (prog->regstart != NUL)
+	    {
+		// Skip until the char we know it must start with.
+		// Used often, do some work to avoid call overhead.
+		if (!rex.reg_ic && !has_mbyte)
+		    s = vim_strbyte(rex.line + col, prog->regstart);
+		else
+		    s = cstrchr(rex.line + col, prog->regstart);
+		if (s == NULL)
+		{
+		    retval = 0;
+		    break;
+		}
+		col = (int)(s - rex.line);
+	    }
+
+	    // Check for maximum column to try.
+	    if (rex.reg_maxcol > 0 && col >= rex.reg_maxcol)
+	    {
+		retval = 0;
+		break;
+	    }
+
+	    retval = regtry(prog, col, tm, timed_out);
+	    if (retval > 0)
+		break;
+
+	    // if not currently on the first line, get it again
+	    if (rex.lnum != 0)
+	    {
+		rex.lnum = 0;
+		rex.line = reg_getline((linenr_T)0);
+	    }
+	    if (rex.line[col] == NUL)
+		break;
+	    if (has_mbyte)
+		col += (*mb_ptr2len)(rex.line + col);
+	    else
+		++col;
+#ifdef FEAT_RELTIME
+	    // Check for timeout once in a twenty times to avoid overhead.
+	    if (tm != NULL && ++tm_count == 20)
+	    {
+		tm_count = 0;
+		if (profile_passed_limit(tm))
+		{
+		    if (timed_out != NULL)
+			*timed_out = TRUE;
+		    break;
+		}
+	    }
+#endif
+	}
+    }
+
+theend:
+    // Free "reg_tofree" when it's a bit big.
+    // Free regstack and backpos if they are bigger than their initial size.
+    if (reg_tofreelen > 400)
+	VIM_CLEAR(reg_tofree);
+    if (regstack.ga_maxlen > REGSTACK_INITIAL)
+	ga_clear(&regstack);
+    if (backpos.ga_maxlen > BACKPOS_INITIAL)
+	ga_clear(&backpos);
+
+    return retval;
+}
+
+/*
+ * Match a regexp against a string.
+ * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
+ * Uses curbuf for line count and 'iskeyword'.
+ * if "line_lbr" is TRUE  consider a "\n" in "line" to be a line break.
+ *
+ * Returns 0 for failure, number of lines contained in the match otherwise.
+ */
+    static int
+bt_regexec_nl(
+    regmatch_T	*rmp,
+    char_u	*line,	// string to match against
+    colnr_T	col,	// column to start looking for match
+    int		line_lbr)
+{
+    rex.reg_match = rmp;
+    rex.reg_mmatch = NULL;
+    rex.reg_maxline = 0;
+    rex.reg_line_lbr = line_lbr;
+    rex.reg_buf = curbuf;
+    rex.reg_win = NULL;
+    rex.reg_ic = rmp->rm_ic;
+    rex.reg_icombine = FALSE;
+    rex.reg_maxcol = 0;
+
+    return bt_regexec_both(line, col, NULL, NULL);
+}
+
+/*
+ * Match a regexp against multiple lines.
+ * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
+ * Uses curbuf for line count and 'iskeyword'.
+ *
+ * Return zero if there is no match.  Return number of lines contained in the
+ * match otherwise.
+ */
+    static long
+bt_regexec_multi(
+    regmmatch_T	*rmp,
+    win_T	*win,		// window in which to search or NULL
+    buf_T	*buf,		// buffer in which to search
+    linenr_T	lnum,		// nr of line to start looking for match
+    colnr_T	col,		// column to start looking for match
+    proftime_T	*tm,		// timeout limit or NULL
+    int		*timed_out)	// flag set on timeout or NULL
+{
+    rex.reg_match = NULL;
+    rex.reg_mmatch = rmp;
+    rex.reg_buf = buf;
+    rex.reg_win = win;
+    rex.reg_firstlnum = lnum;
+    rex.reg_maxline = rex.reg_buf->b_ml.ml_line_count - lnum;
+    rex.reg_line_lbr = FALSE;
+    rex.reg_ic = rmp->rmm_ic;
+    rex.reg_icombine = FALSE;
+    rex.reg_maxcol = rmp->rmm_maxcol;
+
+    return bt_regexec_both(NULL, col, tm, timed_out);
+}
+
+/*
+ * Compare a number with the operand of RE_LNUM, RE_COL or RE_VCOL.
+ */
+    static int
+re_num_cmp(long_u val, char_u *scan)
+{
+    long_u  n = OPERAND_MIN(scan);
+
+    if (OPERAND_CMP(scan) == '>')
+	return val > n;
+    if (OPERAND_CMP(scan) == '<')
+	return val < n;
+    return val == n;
+}
+
+#ifdef BT_REGEXP_DUMP
+
+/*
+ * regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+    static void
+regdump(char_u *pattern, bt_regprog_T *r)
+{
+    char_u  *s;
+    int	    op = EXACTLY;	// Arbitrary non-END op.
+    char_u  *next;
+    char_u  *end = NULL;
+    FILE    *f;
+
+#ifdef BT_REGEXP_LOG
+    f = fopen("bt_regexp_log.log", "a");
+#else
+    f = stdout;
+#endif
+    if (f == NULL)
+	return;
+    fprintf(f, "-------------------------------------\n\r\nregcomp(%s):\r\n", pattern);
+
+    s = r->program + 1;
+    // Loop until we find the END that isn't before a referred next (an END
+    // can also appear in a NOMATCH operand).
+    while (op != END || s <= end)
+    {
+	op = OP(s);
+	fprintf(f, "%2d%s", (int)(s - r->program), regprop(s)); // Where, what.
+	next = regnext(s);
+	if (next == NULL)	// Next ptr.
+	    fprintf(f, "(0)");
+	else
+	    fprintf(f, "(%d)", (int)((s - r->program) + (next - s)));
+	if (end < next)
+	    end = next;
+	if (op == BRACE_LIMITS)
+	{
+	    // Two ints
+	    fprintf(f, " minval %ld, maxval %ld", OPERAND_MIN(s), OPERAND_MAX(s));
+	    s += 8;
+	}
+	else if (op == BEHIND || op == NOBEHIND)
+	{
+	    // one int
+	    fprintf(f, " count %ld", OPERAND_MIN(s));
+	    s += 4;
+	}
+	else if (op == RE_LNUM || op == RE_COL || op == RE_VCOL)
+	{
+	    // one int plus comparator
+	    fprintf(f, " count %ld", OPERAND_MIN(s));
+	    s += 5;
+	}
+	s += 3;
+	if (op == ANYOF || op == ANYOF + ADD_NL
+		|| op == ANYBUT || op == ANYBUT + ADD_NL
+		|| op == EXACTLY)
+	{
+	    // Literal string, where present.
+	    fprintf(f, "\nxxxxxxxxx\n");
+	    while (*s != NUL)
+		fprintf(f, "%c", *s++);
+	    fprintf(f, "\nxxxxxxxxx\n");
+	    s++;
+	}
+	fprintf(f, "\r\n");
+    }
+
+    // Header fields of interest.
+    if (r->regstart != NUL)
+	fprintf(f, "start `%s' 0x%x; ", r->regstart < 256
+		? (char *)transchar(r->regstart)
+		: "multibyte", r->regstart);
+    if (r->reganch)
+	fprintf(f, "anchored; ");
+    if (r->regmust != NULL)
+	fprintf(f, "must have \"%s\"", r->regmust);
+    fprintf(f, "\r\n");
+
+#ifdef BT_REGEXP_LOG
+    fclose(f);
+#endif
+}
+#endif	    // BT_REGEXP_DUMP
+
+#ifdef DEBUG
+/*
+ * regprop - printable representation of opcode
+ */
+    static char_u *
+regprop(char_u *op)
+{
+    char	    *p;
+    static char	    buf[50];
+
+    STRCPY(buf, ":");
+
+    switch ((int) OP(op))
+    {
+      case BOL:
+	p = "BOL";
+	break;
+      case EOL:
+	p = "EOL";
+	break;
+      case RE_BOF:
+	p = "BOF";
+	break;
+      case RE_EOF:
+	p = "EOF";
+	break;
+      case CURSOR:
+	p = "CURSOR";
+	break;
+      case RE_VISUAL:
+	p = "RE_VISUAL";
+	break;
+      case RE_LNUM:
+	p = "RE_LNUM";
+	break;
+      case RE_MARK:
+	p = "RE_MARK";
+	break;
+      case RE_COL:
+	p = "RE_COL";
+	break;
+      case RE_VCOL:
+	p = "RE_VCOL";
+	break;
+      case BOW:
+	p = "BOW";
+	break;
+      case EOW:
+	p = "EOW";
+	break;
+      case ANY:
+	p = "ANY";
+	break;
+      case ANY + ADD_NL:
+	p = "ANY+NL";
+	break;
+      case ANYOF:
+	p = "ANYOF";
+	break;
+      case ANYOF + ADD_NL:
+	p = "ANYOF+NL";
+	break;
+      case ANYBUT:
+	p = "ANYBUT";
+	break;
+      case ANYBUT + ADD_NL:
+	p = "ANYBUT+NL";
+	break;
+      case IDENT:
+	p = "IDENT";
+	break;
+      case IDENT + ADD_NL:
+	p = "IDENT+NL";
+	break;
+      case SIDENT:
+	p = "SIDENT";
+	break;
+      case SIDENT + ADD_NL:
+	p = "SIDENT+NL";
+	break;
+      case KWORD:
+	p = "KWORD";
+	break;
+      case KWORD + ADD_NL:
+	p = "KWORD+NL";
+	break;
+      case SKWORD:
+	p = "SKWORD";
+	break;
+      case SKWORD + ADD_NL:
+	p = "SKWORD+NL";
+	break;
+      case FNAME:
+	p = "FNAME";
+	break;
+      case FNAME + ADD_NL:
+	p = "FNAME+NL";
+	break;
+      case SFNAME:
+	p = "SFNAME";
+	break;
+      case SFNAME + ADD_NL:
+	p = "SFNAME+NL";
+	break;
+      case PRINT:
+	p = "PRINT";
+	break;
+      case PRINT + ADD_NL:
+	p = "PRINT+NL";
+	break;
+      case SPRINT:
+	p = "SPRINT";
+	break;
+      case SPRINT + ADD_NL:
+	p = "SPRINT+NL";
+	break;
+      case WHITE:
+	p = "WHITE";
+	break;
+      case WHITE + ADD_NL:
+	p = "WHITE+NL";
+	break;
+      case NWHITE:
+	p = "NWHITE";
+	break;
+      case NWHITE + ADD_NL:
+	p = "NWHITE+NL";
+	break;
+      case DIGIT:
+	p = "DIGIT";
+	break;
+      case DIGIT + ADD_NL:
+	p = "DIGIT+NL";
+	break;
+      case NDIGIT:
+	p = "NDIGIT";
+	break;
+      case NDIGIT + ADD_NL:
+	p = "NDIGIT+NL";
+	break;
+      case HEX:
+	p = "HEX";
+	break;
+      case HEX + ADD_NL:
+	p = "HEX+NL";
+	break;
+      case NHEX:
+	p = "NHEX";
+	break;
+      case NHEX + ADD_NL:
+	p = "NHEX+NL";
+	break;
+      case OCTAL:
+	p = "OCTAL";
+	break;
+      case OCTAL + ADD_NL:
+	p = "OCTAL+NL";
+	break;
+      case NOCTAL:
+	p = "NOCTAL";
+	break;
+      case NOCTAL + ADD_NL:
+	p = "NOCTAL+NL";
+	break;
+      case WORD:
+	p = "WORD";
+	break;
+      case WORD + ADD_NL:
+	p = "WORD+NL";
+	break;
+      case NWORD:
+	p = "NWORD";
+	break;
+      case NWORD + ADD_NL:
+	p = "NWORD+NL";
+	break;
+      case HEAD:
+	p = "HEAD";
+	break;
+      case HEAD + ADD_NL:
+	p = "HEAD+NL";
+	break;
+      case NHEAD:
+	p = "NHEAD";
+	break;
+      case NHEAD + ADD_NL:
+	p = "NHEAD+NL";
+	break;
+      case ALPHA:
+	p = "ALPHA";
+	break;
+      case ALPHA + ADD_NL:
+	p = "ALPHA+NL";
+	break;
+      case NALPHA:
+	p = "NALPHA";
+	break;
+      case NALPHA + ADD_NL:
+	p = "NALPHA+NL";
+	break;
+      case LOWER:
+	p = "LOWER";
+	break;
+      case LOWER + ADD_NL:
+	p = "LOWER+NL";
+	break;
+      case NLOWER:
+	p = "NLOWER";
+	break;
+      case NLOWER + ADD_NL:
+	p = "NLOWER+NL";
+	break;
+      case UPPER:
+	p = "UPPER";
+	break;
+      case UPPER + ADD_NL:
+	p = "UPPER+NL";
+	break;
+      case NUPPER:
+	p = "NUPPER";
+	break;
+      case NUPPER + ADD_NL:
+	p = "NUPPER+NL";
+	break;
+      case BRANCH:
+	p = "BRANCH";
+	break;
+      case EXACTLY:
+	p = "EXACTLY";
+	break;
+      case NOTHING:
+	p = "NOTHING";
+	break;
+      case BACK:
+	p = "BACK";
+	break;
+      case END:
+	p = "END";
+	break;
+      case MOPEN + 0:
+	p = "MATCH START";
+	break;
+      case MOPEN + 1:
+      case MOPEN + 2:
+      case MOPEN + 3:
+      case MOPEN + 4:
+      case MOPEN + 5:
+      case MOPEN + 6:
+      case MOPEN + 7:
+      case MOPEN + 8:
+      case MOPEN + 9:
+	sprintf(buf + STRLEN(buf), "MOPEN%d", OP(op) - MOPEN);
+	p = NULL;
+	break;
+      case MCLOSE + 0:
+	p = "MATCH END";
+	break;
+      case MCLOSE + 1:
+      case MCLOSE + 2:
+      case MCLOSE + 3:
+      case MCLOSE + 4:
+      case MCLOSE + 5:
+      case MCLOSE + 6:
+      case MCLOSE + 7:
+      case MCLOSE + 8:
+      case MCLOSE + 9:
+	sprintf(buf + STRLEN(buf), "MCLOSE%d", OP(op) - MCLOSE);
+	p = NULL;
+	break;
+      case BACKREF + 1:
+      case BACKREF + 2:
+      case BACKREF + 3:
+      case BACKREF + 4:
+      case BACKREF + 5:
+      case BACKREF + 6:
+      case BACKREF + 7:
+      case BACKREF + 8:
+      case BACKREF + 9:
+	sprintf(buf + STRLEN(buf), "BACKREF%d", OP(op) - BACKREF);
+	p = NULL;
+	break;
+      case NOPEN:
+	p = "NOPEN";
+	break;
+      case NCLOSE:
+	p = "NCLOSE";
+	break;
+#ifdef FEAT_SYN_HL
+      case ZOPEN + 1:
+      case ZOPEN + 2:
+      case ZOPEN + 3:
+      case ZOPEN + 4:
+      case ZOPEN + 5:
+      case ZOPEN + 6:
+      case ZOPEN + 7:
+      case ZOPEN + 8:
+      case ZOPEN + 9:
+	sprintf(buf + STRLEN(buf), "ZOPEN%d", OP(op) - ZOPEN);
+	p = NULL;
+	break;
+      case ZCLOSE + 1:
+      case ZCLOSE + 2:
+      case ZCLOSE + 3:
+      case ZCLOSE + 4:
+      case ZCLOSE + 5:
+      case ZCLOSE + 6:
+      case ZCLOSE + 7:
+      case ZCLOSE + 8:
+      case ZCLOSE + 9:
+	sprintf(buf + STRLEN(buf), "ZCLOSE%d", OP(op) - ZCLOSE);
+	p = NULL;
+	break;
+      case ZREF + 1:
+      case ZREF + 2:
+      case ZREF + 3:
+      case ZREF + 4:
+      case ZREF + 5:
+      case ZREF + 6:
+      case ZREF + 7:
+      case ZREF + 8:
+      case ZREF + 9:
+	sprintf(buf + STRLEN(buf), "ZREF%d", OP(op) - ZREF);
+	p = NULL;
+	break;
+#endif
+      case STAR:
+	p = "STAR";
+	break;
+      case PLUS:
+	p = "PLUS";
+	break;
+      case NOMATCH:
+	p = "NOMATCH";
+	break;
+      case MATCH:
+	p = "MATCH";
+	break;
+      case BEHIND:
+	p = "BEHIND";
+	break;
+      case NOBEHIND:
+	p = "NOBEHIND";
+	break;
+      case SUBPAT:
+	p = "SUBPAT";
+	break;
+      case BRACE_LIMITS:
+	p = "BRACE_LIMITS";
+	break;
+      case BRACE_SIMPLE:
+	p = "BRACE_SIMPLE";
+	break;
+      case BRACE_COMPLEX + 0:
+      case BRACE_COMPLEX + 1:
+      case BRACE_COMPLEX + 2:
+      case BRACE_COMPLEX + 3:
+      case BRACE_COMPLEX + 4:
+      case BRACE_COMPLEX + 5:
+      case BRACE_COMPLEX + 6:
+      case BRACE_COMPLEX + 7:
+      case BRACE_COMPLEX + 8:
+      case BRACE_COMPLEX + 9:
+	sprintf(buf + STRLEN(buf), "BRACE_COMPLEX%d", OP(op) - BRACE_COMPLEX);
+	p = NULL;
+	break;
+      case MULTIBYTECODE:
+	p = "MULTIBYTECODE";
+	break;
+      case NEWL:
+	p = "NEWL";
+	break;
+      default:
+	sprintf(buf + STRLEN(buf), "corrupt %d", OP(op));
+	p = NULL;
+	break;
+    }
+    if (p != NULL)
+	STRCAT(buf, p);
+    return (char_u *)buf;
+}
+#endif	    // DEBUG
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2005,
+/**/
     2004,
 /**/
     2003,