;
	*stackp++ = b - bufp->buffer;
	BUFPUSH(0);	/* temporary value */
	BUFPUSH(0);
	break;

      case ':':
	BUFPUSH(start_paren);
	pending_exact = 0;
      default:
	break;
      }
	if (push_option) {
	  BUFPUSH(option_set);
	  BUFPUSH(options);
	}
	if (casefold) {
	  if (options & RE_OPTION_IGNORECASE)
	    BUFPUSH(casefold_on);
	  else
	    BUFPUSH(casefold_off);
	}
      *stackp++ = c;
      *stackp++ = old_options;
      fixup_alt_jump = 0;
      laststart = 0;
      begalt = b;
      }
      break;

    case ')':
      if (stackp == stackb) 
	FREE_AND_RETURN(stackb, "unmatched )");

      pending_exact = 0;
      if (fixup_alt_jump) {
	/* Push a dummy failure point at the end of the
	   alternative for a possible future
	   `finalize_jump' to pop.  See comments at
	   `push_dummy_failure' in `re_match'.  */
	BUFPUSH(push_dummy_failure);

	/* We allocated space for this jump when we assigned
	   to `fixup_alt_jump', in the `handle_alt' case below.  */
	store_jump(fixup_alt_jump, jump, b);
      }
      if (options != stackp[-1]) {
	if ((options ^ stackp[-1]) & RE_OPTION_IGNORECASE) {
	  BUFPUSH((options&RE_OPTION_IGNORECASE)?casefold_off:casefold_on);
	}
	if ((options ^ stackp[-1]) != RE_OPTION_IGNORECASE) {
	  BUFPUSH(option_set);
	  BUFPUSH(stackp[-1]);
	}
      }
      p0 = b;
      options = *--stackp;
      switch (c = *--stackp) {
      case '(':
	{
	  char *loc = bufp->buffer + *--stackp;
	  *loc = regnum - stackp[-1];
	  BUFPUSH(stop_memory);
	  BUFPUSH(stackp[-1]);
	  BUFPUSH(regnum - stackp[-1]);
	  stackp--;
	}
	break;

      case '!':
	BUFPUSH(pop_and_fail);
	/* back patch */
	STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2);
	stackp--;
	/* fall through */
      case '=':
	BUFPUSH(stop_nowidth);
	/* tell stack-pos place to start_nowidth */
	STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2);
	BUFPUSH(0);	/* space to hold stack pos */
	BUFPUSH(0);
	stackp--;
	break;

      case '>':
	BUFPUSH(stop_backtrack);
	/* tell stack-pos place to start_nowidth */
	STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2);
	BUFPUSH(0);	/* space to hold stack pos */
	BUFPUSH(0);
	stackp--;
	break;

      case ':':
	BUFPUSH(stop_paren);
	break;

      default:
	break;
      }
      begalt = *--stackp + bufp->buffer;
      stackp--;
      fixup_alt_jump = *stackp ? *stackp + bufp->buffer - 1 : 0;
      laststart = *--stackp + bufp->buffer;
      if (c == '!' || c == '=') laststart = b;
      break;

    case '|':
      /* Insert before the previous alternative a jump which
	 jumps to this alternative if the former fails.  */
      GET_BUFFER_SPACE(3);
      insert_jump(on_failure_jump, begalt, b + 6, b);
      pending_exact = 0;
      b += 3;
      /* The alternative before this one has a jump after it
	 which gets executed if it gets matched.  Adjust that
	 jump so it will jump to this alternative's analogous
	 jump (put in below, which in turn will jump to the next
	 (if any) alternative's such jump, etc.).  The last such
	 jump jumps to the correct final destination.  A picture:
	 _____ _____ 
	 |   | |   |   
	 |   v |   v 
	 a | b   | c   

	 If we are at `b', then fixup_alt_jump right now points to a
	 three-byte space after `a'.  We'll put in the jump, set
	 fixup_alt_jump to right after `b', and leave behind three
	 bytes which we'll fill in when we get to after `c'.  */

      if (fixup_alt_jump)
	store_jump(fixup_alt_jump, jump_past_alt, b);

      /* Mark and leave space for a jump after this alternative,
	 to be filled in later either by next alternative or
	 when know we're at the end of a series of alternatives.  */
      fixup_alt_jump = b;
      GET_BUFFER_SPACE(3);
      b += 3;

      laststart = 0;
      begalt = b;
      break;

    case '{':
      /* If there is no previous pattern, this is an invalid pattern.  */
      if (!laststart) {
	snprintf(error_msg, ERROR_MSG_MAX_SIZE, 
		 "invalid regular expression; there's no previous pattern, to which '{' would define cardinality at %d", 
		 p-pattern);
	FREE_AND_RETURN(stackb, error_msg);
      }
      if( p == pend)
	FREE_AND_RETURN(stackb, "invalid regular expression; '{' can't be last character" );

      beg_interval = p - 1;

      lower_bound = -1;			/* So can see if are set.  */
      upper_bound = -1;
      GET_UNSIGNED_NUMBER(lower_bound);
      if (c == ',') {
	GET_UNSIGNED_NUMBER(upper_bound);
      }
      else
	/* Interval such as `{1}' => match exactly once. */
	upper_bound = lower_bound;

      if (lower_bound < 0 || c != '}')
	goto unfetch_interval;

      if (lower_bound >= RE_DUP_MAX || upper_bound >= RE_DUP_MAX)
	FREE_AND_RETURN(stackb, "too big quantifier in {,}");
      if (upper_bound < 0) upper_bound = RE_DUP_MAX;
      if (lower_bound > upper_bound)
	FREE_AND_RETURN(stackb, "can't do {n,m} with n > m");

      beg_interval = 0;
      pending_exact = 0;

      greedy = 1;
      if (p != pend) {
	PATFETCH(c);
	if (c == '?') greedy = 0;
	else PATUNFETCH;
      }

      if (lower_bound == 0) {
	zero_times_ok = 1;
	if (upper_bound == RE_DUP_MAX) {
	  many_times_ok = 1;
	  goto repeat;
	}
	if (upper_bound == 1) {
	  many_times_ok = 0;
	  goto repeat;
	}
      }
      if (lower_bound == 1) {
	if (upper_bound == 1) {
	  /* No need to repeat */
	  break;
	}
	if (upper_bound == RE_DUP_MAX) {
	  many_times_ok = 1;
	  zero_times_ok = 0;
	  goto repeat;
	}
      }

      /* If upper_bound is zero, don't want to succeed at all; 
	 jump from laststart to b + 3, which will be the end of
	 the buffer after this jump is inserted.  */

      if (upper_bound == 0) {
	GET_BUFFER_SPACE(3);
	insert_jump(jump, laststart, b + 3, b);
	b += 3;
	break;
      }

      /* If lower_bound == upper_bound, repeat count can be removed */
      if (lower_bound == upper_bound) {
	int mcnt;
	int skip_stop_paren = 0;

	if (b[-1] == stop_paren) {
	  skip_stop_paren = 1;
	  b--;
	}

	if (*laststart == exactn && laststart[1]+2 == b - laststart
	    && laststart[1]*lower_bound < 256) {
	  mcnt = laststart[1];
	  GET_BUFFER_SPACE((lower_bound-1)*mcnt);
	  laststart[1] = lower_bound*mcnt;
	  while (--lower_bound) {
	    memcpy(b, laststart+2, mcnt);
	    b += mcnt;
	  }
	  if (skip_stop_paren) BUFPUSH(stop_paren);
	  break;
	}

	if (lower_bound < 5 && b - laststart < 10) {
	  /* 5 and 10 are the magic numbers */

	  mcnt = b - laststart;
	  GET_BUFFER_SPACE((lower_bound-1)*mcnt);
	  while (--lower_bound) {
	    memcpy(b, laststart, mcnt);
	    b += mcnt;
	  }
	  if (skip_stop_paren) BUFPUSH(stop_paren);
	  break;
	}
	if (skip_stop_paren) b++; /* push back stop_paren */
      }

      /* Otherwise, we have a nontrivial interval.  When
	 we're all done, the pattern will look like:
	 set_number_at <jump count> <upper bound>
	 set_number_at <succeed_n count> <lower bound>
	 succeed_n <after jump addr> <succed_n count>
	 <body of loop>
	 jump_n <succeed_n addr> <jump count>
	 (The upper bound and `jump_n' are omitted if
	 `upper_bound' is 1, though.)  */
      { /* If the upper bound is > 1, we need to insert
	   more at the end of the loop.  */
	unsigned nbytes = upper_bound == 1 ? 10 : 20;

	GET_BUFFER_SPACE(nbytes);
	/* Initialize lower bound of the `succeed_n', even
	   though it will be set during matching by its
	   attendant `set_number_at' (inserted next),
	   because `re_compile_fastmap' needs to know.
	   Jump to the `jump_n' we might insert below.  */
	insert_jump_n(succeed_n, laststart, b + (nbytes/2), 
		      b, lower_bound);
	b += 5; 	/* Just increment for the succeed_n here.  */

	/* Code to initialize the lower bound.  Insert 
	   before the `succeed_n'.  The `5' is the last two
	   bytes of this `set_number_at', plus 3 bytes of
	   the following `succeed_n'.  */
	insert_op_2(set_number_at, laststart, b, 5, lower_bound);
	b += 5;

	if (upper_bound > 1) {
	  /* More than one repetition is allowed, so
	     append a backward jump to the `succeed_n'
	     that starts this interval.

	     When we've reached this during matching,
	     we'll have matched the interval once, so
	     jump back only `upper_bound - 1' times.  */
	  GET_BUFFER_SPACE(5);
	  store_jump_n(b, greedy?jump_n:finalize_push_n, laststart + 5,
		       upper_bound - 1);
	  b += 5;

	  /* The location we want to set is the second
	     parameter of the `jump_n'; that is `b-2' as
	     an absolute address.  `laststart' will be
	     the `set_number_at' we're about to insert;
	     `laststart+3' the number to set, the source
	     for the relative address.  But we are
	     inserting into the middle of the pattern --
	     so everything is getting moved up by 5.
	     Conclusion: (b - 2) - (laststart + 3) + 5,
	     i.e., b - laststart.

	     We insert this at the beginning of the loop
	     so that if we fail during matching, we'll
	     reinitialize the bounds.  */
	  insert_op_2(set_number_at, laststart, b, b - laststart,
		      upper_bound - 1);
	  b += 5;
	}
      }
      break;

    unfetch_interval:
      /* If an invalid interval, match the characters as literals.  */
      p = beg_interval;
      beg_interval = 0;

      /* normal_char and normal_backslash need `c'.  */
      PATFETCH(c);	
      goto normal_char;

    case '\\':
      if (p == pend)
	FREE_AND_RETURN(stackb, "invalid regular expression; '\\' can't be last character");
      /* Do not translate the character after the \, so that we can
	 distinguish, e.g., \B from \b, even if we normally would
	 translate, e.g., B to b.  */
      PATFETCH_RAW(c);
      switch (c) {
      case 's':
      case 'S':
      case 'd':
      case 'D':
	while (b - bufp->buffer + 9 + (1 << BYTEWIDTH) / BYTEWIDTH
	       > bufp->allocated)
	  EXTEND_BUFFER;

	laststart = b;
	if (c == 's' || c == 'd') {
	  BUFPUSH(charset);
	}
	else {
	  BUFPUSH(charset_not);
	}

	BUFPUSH((1 << BYTEWIDTH) / BYTEWIDTH);
	memset(b, 0, (1 << BYTEWIDTH) / BYTEWIDTH + 2);
	if (c == 's' || c == 'S') {
	  SET_LIST_BIT(' ');
	  SET_LIST_BIT('\t');
	  SET_LIST_BIT('\n');
	  SET_LIST_BIT('\r');
	  SET_LIST_BIT('\f');
	}
	else {
	  char cc;

	  for (cc = '0'; cc <= '9'; cc++) {
	    SET_LIST_BIT(cc);
	  }
	}

	while ((int)b[-1] > 0 && b[b[-1] - 1] == 0) 
	  b[-1]--; 
	if (b[-1] != (1 << BYTEWIDTH) / BYTEWIDTH)
	  memmove(&b[b[-1]], &b[(1 << BYTEWIDTH) / BYTEWIDTH],
		  2 + EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])*8);
	b += b[-1] + 2 + EXTRACT_UNSIGNED(&b[b[-1]])*8;
	break;

      case 'w':
	laststart = b;
	BUFPUSH(wordchar);
	break;

      case 'W':
	laststart = b;
	BUFPUSH(notwordchar);
	break;

#ifndef RUBY
      case '<':
	BUFPUSH(wordbeg);
	break;

      case '>':
	BUFPUSH(wordend);
	break;
#endif

      case 'b':
	BUFPUSH(wordbound);
	break;

      case 'B':
	BUFPUSH(notwordbound);
	break;

      case 'A':
	BUFPUSH(begbuf);
	break;

      case 'Z':
	if ((bufp->options & RE_OPTION_SINGLELINE) == 0) {
	  BUFPUSH(endbuf2);
	  break;
	}
	/* fall through */
      case 'z':
	BUFPUSH(endbuf);
	break;

      case 'G':
	BUFPUSH(begpos);
	break;

	/* hex */
      case 'x':
	had_mbchar = 0;
	c = scan_hex(p, 2, &numlen);
	if (numlen == 0) goto invalid_escape;
	p += numlen;
	had_num_literal = 1;
	goto numeric_char;

	/* octal */
      case '0':
	had_mbchar = 0;
	c = scan_oct(p, 2, &numlen);
	p += numlen;
	had_num_literal = 1;
	goto numeric_char;

	/* back-ref or octal */
      case '1': case '2': case '3':
      case '4': case '5': case '6':
      case '7': case '8': case '9':
	  PATUNFETCH;
	p0 = p;

	  had_mbchar = 0;
	  c1 = 0;
	  GET_UNSIGNED_NUMBER(c1);
	  if (!ISDIGIT(c)) PATUNFETCH;

	if (9 < c1 && c1 >= regnum) {
	    /* need to get octal */
	  c = scan_oct(p0, 3, &numlen) & 0xff;
	  p = p0 + numlen;
	    c1 = 0;
	    had_num_literal = 1;
	    goto numeric_char;
	  }

	laststart = b;
	BUFPUSH(duplicate);
	BUFPUSH(c1);
	break;

      case 'M':
      case 'C':
      case 'c':
	p0 = --p;
	c = read_special(p, pend, &p0);
	if (c > 255) goto invalid_escape;
	p = p0;
	had_num_literal = 1;
	goto numeric_char;

      default:
	c = read_backslash(c);
	goto normal_char;
      }
      break;

    case '#':
      if (options & RE_OPTION_EXTENDED) {
	while (p != pend) {
	  PATFETCH(c);
	  if (c == '\n') break;
	}
	break;
      }
      goto normal_char;

    case ' ':
    case '\t':
    case '\f':
    case '\r':
    case '\n':
      if (options & RE_OPTION_EXTENDED)
	break;

    default:
    normal_char:		/* Expects the character in `c'.  */
      had_mbchar = 0;
      if (ismbchar(c)) {
	had_mbchar = 1;
	c1 = p - pattern;
      }
    numeric_char:
      nextp = p + mbclen(c) - 1;
      if (!pending_exact || pending_exact + *pending_exact + 1 != b
	  || *pending_exact >= (c1 ? 0176 : 0177)
	  || *nextp == '+' || *nextp == '?'
	  || *nextp == '*' || *nextp == '^'
	  || *nextp == '{') {
	laststart = b;
	BUFPUSH(exactn);
	pending_exact = b;
	BUFPUSH(0);
      }
      if (had_num_literal || c == 0xff) {
	BUFPUSH(0xff);
	(*pending_exact)++;
	had_num_literal = 0;
      }
      BUFPUSH(c);
      (*pending_exact)++;
      if (had_mbchar) {
	int len = mbclen(c) - 1;
	while (len--) {
	  PATFETCH_RAW(c);
	  BUFPUSH(c);
	  (*pending_exact)++;
	}
      }
    }
  }

  if (fixup_alt_jump)
    store_jump(fixup_alt_jump, jump, b);

  if (stackp != stackb)
    FREE_AND_RETURN(stackb, "unmatched (");

  /* set optimize flags */
  laststart = bufp->buffer;
  if (laststart != b) {
    if (*laststart == start_memory) laststart += 3;
    if (*laststart == dummy_failure_jump) laststart += 3;
    else if (*laststart == try_next) laststart += 3;
    if (*laststart == anychar_repeat) {
      bufp->options |= RE_OPTIMIZE_ANCHOR;
    }
  }

  bufp->used = b - bufp->buffer;
  bufp->re_nsub = regnum;
  laststart = bufp->buffer;
  if (laststart != b) {
    if (*laststart == start_memory) laststart += 3;
    if (*laststart == exactn) {
      bufp->options |= RE_OPTIMIZE_EXACTN;
      bufp->must = laststart+1;
    }
  }
  if (!bufp->must) {
    bufp->must = calculate_must_string(bufp->buffer, b);
  }
  if (current_mbctype == MBCTYPE_SJIS) bufp->options |= RE_OPTIMIZE_NO_BM;
  else if (bufp->must) {
    int i;
    int len = (unsigned char)bufp->must[0];

    for (i=1; i<len; i++) {
      if ((unsigned char)bufp->must[i] == 0xff ||
	  (current_mbctype && ismbchar(bufp->must[i]))) {
	bufp->options |= RE_OPTIMIZE_NO_BM;
	break;
      }
    }
    if (!(bufp->options & RE_OPTIMIZE_NO_BM)) {
      bufp->must_skip = (int *) xmalloc((1 << BYTEWIDTH)*sizeof(int));
      bm_init_skip(bufp->must_skip, (unsigned char*)bufp->must+1,
		   (unsigned char)bufp->must[0],
		   (unsigned char*)(MAY_TRANSLATE()?translate:0));
    }
  }

  bufp->regstart = TMALLOC(regnum, unsigned char*);
  bufp->regend = TMALLOC(regnum, unsigned char*);
  bufp->old_regstart = TMALLOC(regnum, unsigned char*);
  bufp->old_regend = TMALLOC(regnum, unsigned char*);
  bufp->reg_info = TMALLOC(regnum, register_info_type);
  bufp->best_regstart = TMALLOC(regnum, unsigned char*);
  bufp->best_regend = TMALLOC(regnum, unsigned char*);
  FREE_AND_RETURN(stackb, 0);

 invalid_pattern:
  FREE_AND_RETURN(stackb, "invalid regular expression");

 end_of_pattern:
  FREE_AND_RETURN(stackb, "premature end of regular expression");

 too_big:
  FREE_AND_RETURN(stackb, "regular expression too big");

 memory_exhausted:
  FREE_AND_RETURN(stackb, "memory exhausted");

 nested_meta:
  FREE_AND_RETURN(stackb, "nested *?+ in regexp");

 invalid_escape:
  FREE_AND_RETURN(stackb, "Invalid escape character syntax");
}

void
re_free_pattern(bufp)
     struct re_pattern_buffer *bufp;
{
  xfree(bufp->buffer);
  xfree(bufp->fastmap);
  if (bufp->must_skip) xfree(bufp->must_skip);

  xfree(bufp->regstart);
  xfree(bufp->regend);
  xfree(bufp->old_regstart);
  xfree(bufp->old_regend);
  xfree(bufp->best_regstart);
  xfree(bufp->best_regend);
  xfree(bufp->reg_info);
  xfree(bufp);
}

/* Store a jump of the form <OPCODE> <relative address>.
   Store in the location FROM a jump operation to jump to relative
   address FROM - TO.  OPCODE is the opcode to store.  */

static void
store_jump(from, opcode, to)
     char *from, *to;
     int opcode;
{
  from[0] = (char)opcode;
  STORE_NUMBER(from + 1, to - (from + 3));
}


/* Open up space before char FROM, and insert there a jump to TO.
   CURRENT_END gives the end of the storage not in use, so we know 
   how much data to copy up. OP is the opcode of the jump to insert.

   If you call this function, you must zero out pending_exact.  */

static void
insert_jump(op, from, to, current_end)
     int op;
     char *from, *to, *current_end;
{
  register char *pfrom = current_end;		/* Copy from here...  */
  register char *pto = current_end + 3;		/* ...to here.  */

  while (pfrom != from)			       
    *--pto = *--pfrom;
  store_jump(from, op, to);
}


/* Store a jump of the form <opcode> <relative address> <n> .

   Store in the location FROM a jump operation to jump to relative
   address FROM - TO.  OPCODE is the opcode to store, N is a number the
   jump uses, say, to decide how many times to jump.

   If you call this function, you must zero out pending_exact.  */

static void
store_jump_n(from, opcode, to, n)
     char *from, *to;
     int opcode;
     unsigned n;
{
  from[0] = (char)opcode;
  STORE_NUMBER(from + 1, to - (from + 3));
  STORE_NUMBER(from + 3, n);
}


/* Similar to insert_jump, but handles a jump which needs an extra
   number to handle minimum and maximum cases.  Open up space at
   location FROM, and insert there a jump to TO.  CURRENT_END gives the
   end of the storage in use, so we know how much data to copy up. OP is
   the opcode of the jump to insert.

   If you call this function, you must zero out pending_exact.  */

static void
insert_jump_n(op, from, to, current_end, n)
     int op;
     char *from, *to, *current_end;
     unsigned n;
{
  register char *pfrom = current_end;		/* Copy from here...  */
  register char *pto = current_end + 5;		/* ...to here.  */

  while (pfrom != from)			       
    *--pto = *--pfrom;
  store_jump_n(from, op, to, n);
}


/* Open up space at location THERE, and insert operation OP.
   CURRENT_END gives the end of the storage in use, so
   we know how much data to copy up.

   If you call this function, you must zero out pending_exact.  */

static void
insert_op(op, there, current_end)
     int op;
     char *there, *current_end;
{
  register char *pfrom = current_end;		/* Copy from here...  */
  register char *pto = current_end + 1;		/* ...to here.  */

  while (pfrom != there)			       
    *--pto = *--pfrom;

  there[0] = (char)op;
}


/* Open up space at location THERE, and insert operation OP followed by
   NUM_1 and NUM_2.  CURRENT_END gives the end of the storage in use, so
   we know how much data to copy up.

   If you call this function, you must zero out pending_exact.  */

static void
insert_op_2(op, there, current_end, num_1, num_2)
     int op;
     char *there, *current_end;
     int num_1, num_2;
{
  register char *pfrom = current_end;		/* Copy from here...  */
  register char *pto = current_end + 5;		/* ...to here.  */

  while (pfrom != there)			       
    *--pto = *--pfrom;

  there[0] = (char)op;
  STORE_NUMBER(there + 1, num_1);
  STORE_NUMBER(there + 3, num_2);
}

