/*
 *  $Id: jikouho_d.c,v 1.6 2002/05/12 22:51:16 hiroo Exp $
 */

/*
 * FreeWnn is a network-extensible Kana-to-Kanji conversion system.
 * This file is part of FreeWnn.
 * 
 * Copyright Kyoto University Research Institute for Mathematical Sciences
 *                 1987, 1988, 1989, 1990, 1991, 1992
 * Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1999
 * Copyright ASTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992
 * Copyright FreeWnn Project 1999, 2000, 2002
 *
 * Maintainer:  FreeWnn Project   <freewnn@tomo.gr.jp>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/************************************************
 *      大文節次候補取りだし                    *
 ************************************************/
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include        <stdio.h>
#include        <ctype.h>
#if STDC_HEADERS
#  include	<stdlib.h>
#else
#  if HAVE_MALLOC_H
#    include <malloc.h>
#  endif
#endif /* STDC_HEADERS */

#include        "commonhd.h"
#include        "de_header.h"
#include        "jdata.h"
#include        "fzk.h"
#include        "kaiseki.h"

#ifdef  CONVERT_from_TOP
static void sbn_set (), sons_set ();
#endif /* CONVERT_from_TOP */

static void dsd_hyouka (), cnt_sbn (), cnt_dbn ();
static int cmp_dsd_dbn (), jkt_dbn (), jkt_sbjunjo (), set_jkt_dai (), zen_sbn (), cnt_par (), cnt_son ();
static struct JKT_SBN *jkt_que_reorder ();

static int yomi_sno_tmp;

/*
 * jkt_get_dai : 次候補 all 取りだし (大文節)
 */
int
#ifdef  NO_FZK
jkt_get_dai (yomi_sno, yomi_eno, beginvect, endvect, endvect1, nmax, dsd_dbn)
#else
jkt_get_dai (yomi_sno, yomi_eno, beginvect, fzkchar, endvect, endvect1, nmax, dsd_dbn)
#endif                          /* NO_FZK */
     int yomi_sno;
     int yomi_eno;
     int beginvect;             /* 前端ベクタ(-1:文節先頭、-2:なんでも)品詞No. */
#ifndef NO_FZK
     w_char *fzkchar;
#endif /* NO_FZK */
     int endvect;               /* 終端ベクタ */
     int endvect1;              /* 終端ベクタ */
     int nmax;                  /* 1大文節中の最大小文節数 */
     struct DSD_DBN **dsd_dbn;
{
  register int i;
  register int cnt;
  struct JKT_DBN *rjkt_dbn = 0;
  register struct DSD_DBN *dbn;
  int divid;

  if (c_env->fzk_fid == -1)
    {
      wnn_errorno = WNN_FZK_FILE_NO_LOAD;
      return (-1);
    }
  ft = (struct FT *) files[c_env->fzk_fid].area;
  if ((cnt = jkt_dbn (yomi_sno, yomi_eno, beginvect,
#ifndef NO_FZK
                      fzkchar,
#endif /* NO_FZK */
                      endvect, endvect1, nmax, &rjkt_dbn)) < 0)
    {
      init_work_areas ();
      return (-1);
    }
  if ((cnt = dbn_set (dsd_dbn, rjkt_dbn)) < 0)
    {
      init_work_areas ();
      return (-1);
    }
  for (dbn = *dsd_dbn, i = cnt; i > 0; i--, dbn++)
    {
      dsd_hyouka (dbn);
      if ((divid = get_jkt_status (dbn->sbn->kangovect, beginvect,
#ifndef NO_FZK
                                   fzkchar,
#endif /* NO_FZK */
                                   &(dbn->sbn->status))) != 0)
        dbn->v_jc = DIVID_HYOUKA (dbn->v_jc, divid);
    }
  /* SORT */
  qsort ((char *) *dsd_dbn, cnt, sizeof (struct DSD_DBN), cmp_dsd_dbn);
  return (cnt);
}

static int
cmp_dsd_dbn (dbn1, dbn2)
     struct DSD_DBN *dbn1;
     struct DSD_DBN *dbn2;
{
  return (dbn2->v_jc - dbn1->v_jc);
}

static void
dsd_hyouka (dbn)
     struct DSD_DBN *dbn;
{
  struct DSD_SBN *sbn;
  int len;                      /* 大文節長 */
  int son_v = 0;
  register int j_c;
  register struct DSD_SBN *s_p;
  int i;

  sbn = dbn->sbn;
  j_c = sbn->bun_jc;
  len = j_c - dbn->bun_m + 1;

  for (i = 0, s_p = sbn; i < dbn->sbncnt; s_p++, i++)
    {
      son_v += s_p->v_jc;
    }

  dbn->v_jc = hyoka_dbn (son_v, dbn->sbncnt, len);
}

/*******************/

static int
#ifdef  NO_FZK
jkt_dbn (yomi_sno, yomi_eno, beginvect, endvect, endvect1, nmax, rjkt_dbn)
#else
jkt_dbn (yomi_sno, yomi_eno, beginvect, fzkchar, endvect, endvect1, nmax, rjkt_dbn)
#endif                          /* NO_FZK */
     int yomi_sno;
     int yomi_eno;
     int beginvect;             /* 前端ベクタ(-1:文節先頭、-2:なんでも)品詞No. */
#ifndef NO_FZK
     w_char *fzkchar;
#endif /* NO_FZK */
     int endvect;               /* 終端ベクタ */
     int endvect1;              /* 終端ベクタ */
     register int nmax;         /* 1大文節中の最大小文節数 */
     struct JKT_DBN **rjkt_dbn; /* 次候補解析結果 */
{
  register struct JKT_SBN **sb_que_head;        /* 小文節解析結果 */
  int tmp;                      /* 次候補ベクター数 */
  struct JKT_SBN *db_tmp;
  register struct JKT_SBN *sb_one;
  struct JKT_SBN *sbn_tmp;
  register struct JKT_SBN **sb_que_newcomer;
  struct JKT_DBN *jktdbn = 0;
  int dbncnt = 0;
#ifndef NO_KANA
  int gijiflag = 0;             /* 疑似文節を作ったか:最初の小文節のみ */
#endif /* NO_KANA */

  yomi_sno_tmp = yomi_sno;

  sb_que_head = &db_tmp;
  *sb_que_head = NULL;

  if ((tmp = zen_sbn (yomi_sno, yomi_eno, endvect, endvect1, sb_que_head, 1, (struct JKT_SBN *) 0
#ifndef NO_KANA
                      , &gijiflag
#endif /* NO_KANA */
       )) <= 0)
    return (tmp);

  while (*sb_que_head != NULL)
    {
      sb_one = *sb_que_head;
      *sb_que_head = sb_one->lnk_br;
      if (nmax > sb_one->kbcnt && yomi_eno > sb_one->j_c + 1)
        {
          sb_que_newcomer = &sbn_tmp;
          *sb_que_newcomer = NULL;
          tmp = zen_sbn (sb_one->j_c + 1, yomi_eno, sb_one->kangovect, WNN_VECT_NO, sb_que_newcomer, sb_one->kbcnt + 1, sb_one
#ifndef NO_KANA
                         , 0
#endif /* NO_KANA */
            );
          if (tmp < 0)
            {
              return (-1);      /* ERROR */
            }
          else if (tmp > 0)
            {
              sb_one->reference += tmp;
              if (*sb_que_head != 0)
                *sb_que_head = jkt_que_reorder (*sb_que_head, *sb_que_newcomer);
              else
                *sb_que_head = *sb_que_newcomer;
            }
          else
            {
              freejktsbn (sb_one);
            }
        }
      else if (yomi_eno == sb_one->j_c + 1)
        {
          if (set_jkt_dai (rjkt_dbn, &jktdbn, sb_one) < 0)
            return (-1);
          dbncnt++;
        }
    }
#ifndef NO_KANA
/* ひらがな候補 */
  if (gijiflag == 0)
    {
      if ((sb_one = get_hira_kouho (&db_tmp, yomi_sno, yomi_eno)) < (struct JKT_SBN *) 0)
        return (-1);

      if (sb_one > (struct JKT_SBN *) 0)
        {
          sb_one->parent = 0;
          sb_one->bend_m = yomi_sno;
          sb_one->kbcnt = 1;
          if (set_jkt_dai (rjkt_dbn, &jktdbn, sb_one) < 0)
            return (-1);
          dbncnt++;
        }
    }
#endif /* NO_KANA */

  return (dbncnt);
}

/* 前(beginvect,fzkchar)と接続できるか調べ、
        接続できるとき          1
        大文節の先頭の時        0
        接続できないとき        -1
   を返す
        get_status 参照
*/

int
#ifdef  NO_FZK
get_jkt_status (kangovect, beginvect, status)
#else
get_jkt_status (kangovect, beginvect, fzkchar, status)
#endif                          /* NO_FZK */
     int kangovect;
     int beginvect;
#ifndef NO_FZK
     w_char *fzkchar;
#endif /* NO_FZK */
     short *status;
{
  extern int _status;
  _status = 0;
  return (get_status (kangovect, beginvect,
#ifndef NO_FZK
                      fzkchar,
#endif /* NO_FZK */
                      status));
}

/*
int
get_dsd_status(kangovect, beginvect, fzkchar, status)
int     kangovect;
int     beginvect;
w_char  *fzkchar;
int     *status;
{
    if (zentan_able(kangovect, beginvect, fzkchar) == YES) {
        if (beginvect == WNN_ALL_HINSI) {
            if (kan_ckvt(sentou_no, kangovect) == WNN_CONNECT_BK) {
                *status = WNN_SENTOU;
            } else {
                *status = WNN_NOT_CONNECT;
                return (-1);
            }
        } else if (beginvect == WNN_BUN_SENTOU) {
                *status = WNN_SENTOU;
        } else {
            if ((fzkchar == NULL || *fzkchar == NULL) && beginvect == sentou_no)
                *status = WNN_SENTOU;
            else
                *status = WNN_CONNECT;
                return (1);
        }
    } else if (kan_ckvt(sentou_no, kangovect) == WNN_CONNECT_BK) {
            sb_one->status = WNN_SENTOU;
    } else {
            *status = WNN_NOT_CONNECT;
            return (-1);
    }
    return(0);
}
*/

/* 小文節の並び替え 長さとベクタでソートする */
/* que の先頭を返す */
static struct JKT_SBN *
jkt_que_reorder (que, new)
     register struct JKT_SBN *que, *new;
{
  struct JKT_SBN *que_sv;
  register struct JKT_SBN *tmp;
  register struct JKT_SBN *next;

  if (new == 0)
    return (que);
  if (jkt_sbjunjo (que, new) < 0)
    {
      que_sv = new;
    }
  else
    que_sv = que;

  while (new != NULL)
    {
      next = new->lnk_br;
      if (jkt_sbjunjo (que, new) < 0)
        {
          /* NEW が前 */
          tmp = que;
          que = new;
          que->lnk_br = tmp;
          new = next;
          continue;
        }
      /* QUE が前 */
      while ((jkt_sbjunjo (que, new) > 0) && que->lnk_br != NULL)
        que = (que->lnk_br);
      tmp = que->lnk_br;
      /* QUE の後にNEW */
      que->lnk_br = new;
      new->lnk_br = tmp;
      new = next;
    }
  return (que_sv);
}

/* que と new の順序
        1: que が前
        0: que の後に new
        -1:new が前
XXXXX   -2:同一順位 */
static int
jkt_sbjunjo (que, new)
     struct JKT_SBN *que, *new;
{
  if (new == 0)
    return (1);
  if (que->j_c > new->j_c)
    return (-1);
  if (que->j_c < new->j_c)
    {
      if (que->lnk_br == 0)
        return (0);
      if (que->lnk_br->j_c > new->j_c)
        return (0);
      if (que->lnk_br->j_c < new->j_c)
        return (1);
      if (que->lnk_br->kangovect > new->kangovect)
        return (0);
      return (1);
    }
  if (que->kangovect == new->kangovect)
    return (0);                 /* return (-2); */
  if (que->kangovect > new->kangovect)
    return (-1);
  if (que->lnk_br == 0)
    return (0);
  if (que->lnk_br->j_c > new->j_c)
    return (0);
  if (que->lnk_br->kangovect > new->kangovect)
    return (0);
  return (1);
}


/* 文節の先頭になれれば、大文節の候補をセットする */
static int
set_jkt_dai (rjkt_dbn, jktdbn, sbn)
     struct JKT_DBN **rjkt_dbn;
     register struct JKT_DBN **jktdbn;
     register struct JKT_SBN *sbn;
{
  struct JKT_DBN *getjktdbn ();

  if (*jktdbn != 0)
    {
      if (((*jktdbn)->lnk_br = getjktdbn ()) == 0)
        return (-1);
      (*jktdbn) = (*jktdbn)->lnk_br;
    }
  else
    {
      if ((*rjkt_dbn = *jktdbn = getjktdbn ()) == 0)
        return (-1);
    }
  (*jktdbn)->j_c = sbn->j_c;
  (*jktdbn)->sbn_cnt = sbn->kbcnt;
  (*jktdbn)->lnk_br = 0;
  (*jktdbn)->sbn = sbn;
  (*jktdbn)->bend_m = yomi_sno_tmp;
  return (0);
}

static int
zen_sbn (yomi_sno, yomi_eno, endvect, endvect1, tjktsbn, bnst_num, parent
#ifndef NO_KANA
         , gijiflagp
#endif                          /* NO_KANA */
  )
     int yomi_sno;
     int yomi_eno;
     int endvect;               /* 終端ベクタ */
     int endvect1;              /* 終端ベクタ */
     struct JKT_SBN **tjktsbn;  /* 小文節解析結果 */
     int bnst_num;              /* これまでに解析した小文節数 */
     struct JKT_SBN *parent;    /* 親の幹語ノード */
#ifndef NO_KANA
     int *gijiflagp;
#endif /* NO_KANA */
{
  register int fzkcnt, ii, jktcnt;
  register int i,               /* 幹語の終わりのインデックス */
    j;                          /* 文節始めのインデックス */
  struct JKT_SBN *jktsbn_top = 0;
  struct ICHBNP *ichbnpbp;
  struct JKT_SBN *gijisbn_top;
  int get_giji_flg = -1;        /* 擬似文節を作れたか */
  int cnt;
#ifndef NO_KANA
  struct JKT_SBN *jktsbn;
  int index_tmp;
  struct fzkkouho *fzkptr;
  int *vector1;
#endif

#ifndef NO_KATA
  struct JKT_SBN *get_kata_kouho ();
#endif
  struct JKT_SBN *get_hira_kouho ();
  struct SYO_BNSETSU *giji_sbn;
  struct SYO_BNSETSU *getsbnsp ();

  if (yomi_sno == yomi_eno)
    return (NOTHING);

  if (fzk_ckvt (endvect) == NO && fzk_ckvt (endvect1) == NO)
    return (NOTHING);
  fzkcnt = fzk_kai (&bun[yomi_sno], &bun[yomi_eno], endvect, endvect1, &ichbnpbp);
  if (fzkcnt <= 0)
    return (fzkcnt);            /* ERROR */
  for (ii = 0; ii < fzkcnt; ii++)
    getfzkoh (ichbnpbp, ii)->offset += yomi_sno;


  for (ii = 0; ii < fzkcnt; ii++)
    {
      i = getfzkoh (ichbnpbp, ii)->offset;
      if (jmtp[i] == (struct jdata **) UN_KNOWN)        /* もう引いた? */
        jmt_set (i);            /* 辞書引き */
    }

  j = j_max (ichbnpbp, fzkcnt);
  j = (j >= yomi_eno) ? yomi_eno - 1 : j;

  jktcnt = 0;

#if     !defined(NO_KANA) && !defined(KOREAN)
/* カタカナ疑似文節を取り出します */
  if (gijiflagp != 0 && j < yomi_eno - 1)
    {
      for (ii = 0; ii < fzkcnt; ii++)
        {                       /* 付属語 */
          fzkptr = getfzkoh (ichbnpbp, ii);
          if (bnst_num == 1)
            vector1 = getfzkoh1 (ichbnpbp, ii)->vector;
          else
            vector1 = fzkptr->vector;
          index_tmp = fzkptr->offset;
          if ((jktsbn = get_kata_kouho (&jktsbn_top, yomi_sno, yomi_eno, fzkptr->offset, fzkptr->vector, vector1, ii)) < (struct JKT_SBN *) 0)

            return (-1);
          if (jktsbn > (struct JKT_SBN *) 0)
            {
              jktsbn->parent = parent;
              jktsbn->bend_m = yomi_sno;
              jktsbn->kbcnt = bnst_num;
              jktcnt++;
            }
        }                       /* 付属語 */
    }
#endif /* !defined(NO_KANA) && !defined(KOREAN) */
  if ((giji_sbn = getsbnsp ()) == NO)
    return (-1);
  gijisbn_top = 0;
  giji_sbn->bend_m = yomi_sno;
  if (getgiji (yomi_sno, yomi_eno, giji_sbn, ichbnpbp, fzkcnt, bnst_num) >= 0)
    {
      if (giji_sbn->hinsi_fk != katakanago_no && giji_sbn->hinsi_fk != giji_no && giji_sbn->hinsi_fk != fuzokugo_no)
        {
          if (get_zen_giji (giji_sbn, &gijisbn_top) < 0)
            return (-1);
          gijisbn_top->parent = parent;
          gijisbn_top->kbcnt = bnst_num;
          get_giji_flg = giji_sbn->j_c;
#ifndef NO_KANA
          if (gijiflagp != 0 && giji_sbn->j_c == yomi_eno - 1)
            *gijiflagp = 1;
#endif /* NO_KANA */
          jktcnt++;
        }
    }
  freesbn (giji_sbn);

  if (gijisbn_top != 0)
    {
      if (get_giji_flg > j)
        {
          gijisbn_top->lnk_br = jktsbn_top;
          jktsbn_top = gijisbn_top;
          get_giji_flg = -1;
        }
    }

  for (; j >= yomi_sno; j--)
    {
      /* 文節の長さ */
      if (get_giji_flg == j)
        {
          gijisbn_top->lnk_br = jktsbn_top;
          jktsbn_top = gijisbn_top;
          get_giji_flg = -1;
        }
      if ((cnt = jkt_sbn_one (yomi_sno, j + 1, &jktsbn_top, bnst_num, parent, ichbnpbp, fzkcnt)) < 0)
        return (-1);
      jktcnt += cnt;

    }
  *tjktsbn = jktsbn_top;        /* 短いものから並べる */
  freeibsp (ichbnpbp);
  return (jktcnt);
}

struct DSD_DBN *
get_dsd_dbn (cnt)
     register int cnt;
{
  static struct DSD_DBN *m_dbn = 0;
  static int md_cnt = 0;

  if (md_cnt < cnt)
    {
      /* どんどんふくれる Jserver */
      if (m_dbn)
        free (m_dbn);
      m_dbn = (struct DSD_DBN *) malloc (cnt * sizeof (struct DSD_DBN));
      if (m_dbn == NULL)
        {
          /* 大きくなって天まで届け! */
          wnn_errorno = WNN_JKTAREA_FULL;
          error1 ("malloc err in dbn_set (at daibnsetsu jikouho).\n");
          md_cnt = 0;
          return ((struct DSD_DBN *) -1);
        }
      else
        md_cnt = cnt;
    }
  return (m_dbn);
}

struct DSD_SBN *
get_dsd_sbn (cnt)
     register int cnt;
{
  static struct DSD_SBN *m_sbn = 0;
  static int ms_cnt = 0;

  if (ms_cnt < cnt)
    {
      if (m_sbn)
        free (m_sbn);
      m_sbn = (struct DSD_SBN *) malloc (cnt * sizeof (struct DSD_SBN));
      if (m_sbn == NULL)
        {
          wnn_errorno = WNN_JKTAREA_FULL;
          error1 ("malloc err in dbn_set (at daibnsetsu jikouho).\n");
          ms_cnt = 0;
          return ((struct DSD_SBN *) -1);
        }
      else
        ms_cnt = cnt;
    }
  return (m_sbn);
}

int
dbn_set (dsd_dbn, dbn)
     struct DSD_DBN **dsd_dbn;
     register struct JKT_DBN *dbn;
{
  register struct JKT_SBN *sbn;
  register struct JKT_SONE *sone;
  int i;
#ifndef CONVERT_from_TOP
  int j, son, par;
#endif
  struct JKT_DBN *next_dbn;

  int cnt;
  int dbn_cnt;
  int sbn_cnt;
  struct DSD_DBN *d_dbn;
  struct DSD_SBN *d_sbn;
  register struct DSD_SBN *p_sbn;
  struct DSD_SBN *sv_sbn;

  cnt_dbn (dbn, &cnt, &sbn_cnt);

  if ((d_dbn = *dsd_dbn = get_dsd_dbn (cnt)) <= (struct DSD_DBN *) 0)
    return (-1);
  if ((sv_sbn = d_sbn = get_dsd_sbn (sbn_cnt)) <= (struct DSD_SBN *) 0)
    return (-1);

  while (dbn)
    {
      sbn = dbn->sbn;
      cnt_sbn (sbn, &dbn_cnt, &sbn_cnt);
      p_sbn = d_sbn = sv_sbn;
      sv_sbn += sbn_cnt;
      for (i = 0; i < dbn_cnt; i++)
        {
          d_dbn->bun_m = dbn->bend_m;
          d_dbn->bun_jc = dbn->j_c;
          d_dbn->sbncnt = dbn->sbn_cnt;
          d_dbn->sbn = p_sbn;
          p_sbn += dbn->sbn_cnt;
          d_dbn++;
        }
#ifdef  CONVERT_from_TOP
      sbn_set (dbn, &d_sbn, sone, dbn->sbn);

      next_dbn = dbn->lnk_br;
      freejktdbn (dbn);
      dbn = next_dbn;
#else /* CONVERT_from_TOP */
      for (sbn = dbn->sbn; sbn != 0; sbn = sbn->parent, d_sbn++)
        {
          son = cnt_son (dbn->sbn, sbn);
          par = cnt_par (sbn);
          p_sbn = d_sbn;
          for (j = 0; j < son; j++)
            {
              for (sone = sbn->sbn; sone != 0; sone = sone->lnk_br)
                {
                  for (i = 0; i < par; i++)
                    {
                      p_sbn->bun_m = sbn->bend_m;
                      p_sbn->bun_jc = sbn->j_c;
                      p_sbn->i_jc = sone->i_jc;
                      p_sbn->jentptr = sone->jentptr;
                      p_sbn->t_jc = sone->t_jc;
                      p_sbn->hinsi = sone->hinsi_fk;
                      p_sbn->kangovect = sbn->kangovect;
                      p_sbn->v_jc = sone->v_jc;
                      p_sbn->status_bkwd = sone->status_bkwd;
                      if (sbn->status == WNN_NOT_CONNECT && sone->jentptr == 0)
                        p_sbn->status = WNN_GIJI;
                      else
                        p_sbn->status = sbn->status;
                      p_sbn += dbn->sbn_cnt;
                    }
                }
            }
        }
      next_dbn = dbn->lnk_br;
      freejktdbn (dbn);
      dbn = next_dbn;
#endif /* CONVERT_from_TOP */
    }
  return (cnt);
}

#ifdef  CONVERT_from_TOP
static void
sbn_set (dbn, pr_d_sbn, sone, sbn)
     register struct JKT_DBN *dbn;
     register struct DSD_SBN **pr_d_sbn;
     register struct JKT_SONE *sone;
     register struct JKT_SBN *sbn;
{
  int son, par;
  register struct DSD_SBN *p_sbn;
  if (sbn != 0)
    {
      sbn_set (dbn, pr_d_sbn, sone, sbn->parent);

      son = cnt_son (dbn->sbn, sbn);
      par = cnt_par (sbn);
      p_sbn = *pr_d_sbn;
      sons_set (dbn, sone, sbn, p_sbn, son, par);

      (*pr_d_sbn)++;
    }
}

static void
sons_set (dbn, sone, sbn, p_sbn, son, par)
     register struct JKT_DBN *dbn;
     register struct JKT_SONE *sone;
     register struct JKT_SBN *sbn;
     register struct DSD_SBN *p_sbn;
     register int son, par;
{
  register int i, j;

  for (j = 0; j < son; j++)
    {
      for (sone = sbn->sbn; sone != 0; sone = sone->lnk_br)
        {
          for (i = 0; i < par; i++)
            {
              p_sbn->bun_m = sbn->bend_m;
              p_sbn->bun_jc = sbn->j_c;
              p_sbn->i_jc = sone->i_jc;
              p_sbn->jentptr = sone->jentptr;
              p_sbn->t_jc = sone->t_jc;
              p_sbn->hinsi = sone->hinsi_fk;
              p_sbn->kangovect = sbn->kangovect;
              p_sbn->v_jc = sone->v_jc;
              p_sbn->status_bkwd = sone->status_bkwd;
              if (sbn->status == WNN_NOT_CONNECT && sone->jentptr == 0)
                p_sbn->status = WNN_GIJI;
              else
                p_sbn->status = sbn->status;
              p_sbn += dbn->sbn_cnt;
            }
        }
    }
}
#endif /* CONVERT_from_TOP */

/* 小文節の次候補の数 */
int
cnt_sone (sone)
     register struct JKT_SONE *sone;
{
  register int i = 0;
  while (sone)
    {
      i++;
      sone = sone->lnk_br;
    }
  return (i);
}

/* その文節以後の総文節数 */
static int
cnt_par (sbn)
     register struct JKT_SBN *sbn;
{
  register int cnt;
  cnt = 1;
  while (sbn->parent)
    {
      sbn = sbn->parent;
      cnt *= cnt_sone (sbn->sbn);
    }
  return (cnt);
}

/* その文節以前の総文節数 */
static int
cnt_son (son, sbn)
     register struct JKT_SBN *son;
     register struct JKT_SBN *sbn;
{
  register int cnt;
  cnt = 1;
  while (son != sbn)
    {
      cnt *= cnt_sone (son->sbn);
      son = son->parent;
    }
  return (cnt);
}

/* 1 大文節中の小文節の数 */
static void
cnt_sbn (sbn, d_cnt, s_cnt)
     register struct JKT_SBN *sbn;
     register int *d_cnt;
     register int *s_cnt;
{
  *s_cnt = 0;
  *d_cnt = 1;
  while (sbn)
    {
      *d_cnt *= cnt_sone (sbn->sbn);
      (*s_cnt)++;
      sbn = sbn->parent;
    }
  *s_cnt *= *d_cnt;
}

/* 1 大文節の数 */
static void
cnt_dbn (dbn, dbn_cnt, sbn_cnt)
     register struct JKT_DBN *dbn;
     register int *dbn_cnt;
     register int *sbn_cnt;
{
  int dbn_cnt_tmp;
  int sbn_cnt_tmp;

  *dbn_cnt = 0;
  *sbn_cnt = 0;
  while (dbn)
    {
      cnt_sbn (dbn->sbn, &dbn_cnt_tmp, &sbn_cnt_tmp);
      *dbn_cnt += dbn_cnt_tmp;
      *sbn_cnt += sbn_cnt_tmp;
      dbn = dbn->lnk_br;
    }
}
