compile_quantifier_node(QtfrNode* qn, regex_t* reg)
{
  int r, mod_tlen;
  int ckn;
  int infinite = IS_REPEAT_INFINITE(qn->upper);
  int empty_info = qn->target_empty_info;
  int tlen = compile_length_tree(qn->target, reg);

  if (tlen < 0) return tlen;

  ckn = ((reg->num_comb_exp_check > 0) ? qn->comb_exp_check_num : 0);

  if (is_anychar_star_quantifier(qn)) {
    r = compile_tree_n_times(qn->target, qn->lower, reg);
    if (r) return r;
    if (IS_NOT_NULL(qn->next_head_exact) && !CKN_ON) {
      if (IS_MULTILINE(reg->options))
	r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT);
      else
	r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT);
      if (r) return r;
      if (CKN_ON) {
	r = add_state_check_num(reg, ckn);
	if (r) return r;
      }

      return add_bytes(reg, NSTR(qn->next_head_exact)->s, 1);
    }
    else {
      if (IS_MULTILINE(reg->options)) {
	r = add_opcode(reg, (CKN_ON ?
			       OP_STATE_CHECK_ANYCHAR_ML_STAR
			     : OP_ANYCHAR_ML_STAR));
      }
      else {
	r = add_opcode(reg, (CKN_ON ?
			       OP_STATE_CHECK_ANYCHAR_STAR
			     : OP_ANYCHAR_STAR));
      }
      if (r) return r;
      if (CKN_ON)
	r = add_state_check_num(reg, ckn);

      return r;
    }
  }

  if (empty_info != 0)
    mod_tlen = tlen + (SIZE_OP_NULL_CHECK_START + SIZE_OP_NULL_CHECK_END);
  else
    mod_tlen = tlen;

  if (infinite && qn->lower <= 1) {
    if (qn->greedy) {
      if (qn->lower == 1) {
	r = add_opcode_rel_addr(reg, OP_JUMP,
			(CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH));
	if (r) return r;
      }

      if (CKN_ON) {
	r = add_opcode(reg, OP_STATE_CHECK_PUSH);
	if (r) return r;
	r = add_state_check_num(reg, ckn);
	if (r) return r;
	r = add_rel_addr(reg, mod_tlen + SIZE_OP_JUMP);
      }
      else {
	r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP);
      }
      if (r) return r;
      r = compile_tree_empty_check(qn->target, reg, empty_info);
      if (r) return r;
      r = add_opcode_rel_addr(reg, OP_JUMP,
	      -(mod_tlen + (int )SIZE_OP_JUMP
		+ (int )(CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH)));
    }
    else {
      if (qn->lower == 0) {
	r = add_opcode_rel_addr(reg, OP_JUMP, mod_tlen);
	if (r) return r;
      }
      r = compile_tree_empty_check(qn->target, reg, empty_info);
      if (r) return r;
      if (CKN_ON) {
	r = add_opcode(reg, OP_STATE_CHECK_PUSH_OR_JUMP);
	if (r) return r;
	r = add_state_check_num(reg, ckn);
	if (r) return r;
	r = add_rel_addr(reg,
		 -(mod_tlen + (int )SIZE_OP_STATE_CHECK_PUSH_OR_JUMP));
      }
      else
	r = add_opcode_rel_addr(reg, OP_PUSH, -(mod_tlen + (int )SIZE_OP_PUSH));
    }
  }
  else if (qn->upper == 0) {
    if (qn->is_refered != 0) { /* /(?<n>..){0}/ */
      r = add_opcode_rel_addr(reg, OP_JUMP, tlen);
      if (r) return r;
      r = compile_tree(qn->target, reg);
    }
    else
      r = 0;
  }
  else if (qn->upper == 1 && qn->greedy) {
    if (qn->lower == 0) {
      if (CKN_ON) {
	r = add_opcode(reg, OP_STATE_CHECK_PUSH);
	if (r) return r;
	r = add_state_check_num(reg, ckn);
	if (r) return r;
	r = add_rel_addr(reg, tlen);
      }
      else {
	r = add_opcode_rel_addr(reg, OP_PUSH, tlen);
      }
      if (r) return r;
    }

    r = compile_tree(qn->target, reg);
  }
  else if (!qn->greedy && qn->upper == 1 && qn->lower == 0) { /* '??' */
    if (CKN_ON) {
      r = add_opcode(reg, OP_STATE_CHECK_PUSH);
      if (r) return r;
      r = add_state_check_num(reg, ckn);
      if (r) return r;
      r = add_rel_addr(reg, SIZE_OP_JUMP);
    }
    else {
      r = add_opcode_rel_addr(reg, OP_PUSH, SIZE_OP_JUMP);
    }

    if (r) return r;
    r = add_opcode_rel_addr(reg, OP_JUMP, tlen);
    if (r) return r;
    r = compile_tree(qn->target, reg);
  }
  else {
    r = compile_range_repeat_node(qn, mod_tlen, empty_info, reg);
    if (CKN_ON) {
      if (r) return r;
      r = add_opcode(reg, OP_STATE_CHECK);
      if (r) return r;
      r = add_state_check_num(reg, ckn);
    }
  }
  return r;
}