Fix license
[platform/core/uifw/anthy.git] / src-splitter / metaword.c
1 /*
2  * Ê¸Àá¤â¤·¤¯¤Ïñ¸ì¤ò°ì¤Ä°Ê¾å¥»¥Ã¥È¤Ë¤·¤Æmetaword¤È¤·¤Æ°·¤¦¡£
3  * ¤³¤³¤Ç¤Ï³Æ¼ï¤Îmetaword¤òÀ¸À®¤¹¤ë
4  *
5  * init_metaword_tab() metaword½èÍý¤Î¤¿¤á¤Î¾ðÊó¤ò¹½À®¤¹¤ë
6  * anthy_make_metaword_all() contextÃæ¤Îmetaword¤ò¹½À®¤¹¤ë
7  * anthy_print_metaword() »ØÄꤵ¤ì¤¿metaword¤òɽ¼¨¤¹¤ë
8  *
9  * Funded by IPA̤Ƨ¥½¥Õ¥È¥¦¥§¥¢ÁϤ»ö¶È 2001 10/29
10  * Copyright (C) 2000-2006 TABATA Yusuke
11  * Copyright (C) 2004-2006 YOSHIDA Yuichi
12  * Copyright (C) 2000-2003 UGAWA Tomoharu
13  */
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <math.h>
17
18 #include <anthy/record.h>
19 #include <anthy/splitter.h>
20 #include <anthy/xchar.h>
21 #include <anthy/xstr.h>
22 #include <anthy/segment.h>
23 #include <anthy/segclass.h>
24 #include "wordborder.h"
25
26 /* ³Æ¼ïmeta_word¤ò¤É¤Î¤è¤¦¤Ë½èÍý¤¹¤ë¤« */
27 struct metaword_type_tab_ anthy_metaword_type_tab[] = {
28   {MW_DUMMY,"dummy",MW_STATUS_NONE,MW_CHECK_SINGLE},
29   {MW_SINGLE,"single",MW_STATUS_NONE,MW_CHECK_SINGLE},
30   {MW_WRAP,"wrap",MW_STATUS_WRAPPED,MW_CHECK_WRAP},
31   {MW_COMPOUND_HEAD,"compound_head",MW_STATUS_NONE,MW_CHECK_COMPOUND},
32   {MW_COMPOUND,"compound",MW_STATUS_NONE,MW_CHECK_NONE},
33   {MW_COMPOUND_LEAF,"compound_leaf",MW_STATUS_COMPOUND,MW_CHECK_NONE},
34   {MW_COMPOUND_PART,"compound_part",MW_STATUS_COMPOUND_PART,MW_CHECK_SINGLE},
35   {MW_V_RENYOU_A,"v_renyou_a",MW_STATUS_COMBINED,MW_CHECK_BORDER},
36   {MW_V_RENYOU_NOUN,"v_renyou_noun",MW_STATUS_COMBINED,MW_CHECK_BORDER},
37   {MW_NUMBER,"number",MW_STATUS_COMBINED,MW_CHECK_NUMBER},
38   {MW_OCHAIRE,"ochaire",MW_STATUS_OCHAIRE,MW_CHECK_OCHAIRE},
39   /**/
40   {MW_END,"end",MW_STATUS_NONE,MW_CHECK_NONE}
41 };
42
43 static void
44 combine_metaword(struct splitter_context *sc, struct meta_word *mw);
45
46 /* ¥³¥ó¥Æ¥­¥¹¥ÈÃæ¤Ëmetaword¤òÄɲ乤ë */
47 void
48 anthy_commit_meta_word(struct splitter_context *sc,
49                        struct meta_word *mw)
50 {
51   struct word_split_info_cache *info = sc->word_split_info;
52   /* Æ±¤¸³«»ÏÅÀ¤ò»ý¤Ä¥Î¡¼¥É¤Î¥ê¥¹¥È */
53   mw->next = info->cnode[mw->from].mw;
54   info->cnode[mw->from].mw = mw;
55   /**/
56   if (anthy_splitter_debug_flags() & SPLITTER_DEBUG_MW) {
57     anthy_print_metaword(sc, mw);
58   }
59 }
60
61 static void
62 print_metaword_features(int features)
63 {
64   if (features & MW_FEATURE_SV) {
65     printf(":sv");
66   }
67   if (features & MW_FEATURE_WEAK_CONN) {
68     printf(":weak");
69   }
70   if (features & MW_FEATURE_SUFFIX) {
71     printf(":suffix");
72   }
73   if (features & MW_FEATURE_NUM) {
74     printf(":num");
75   }
76   if (features & MW_FEATURE_CORE1) {
77     printf(":c1");
78   }
79   if (features & MW_FEATURE_HIGH_FREQ) {
80     printf(":hf");
81   }
82 }
83
84 static void
85 anthy_do_print_metaword(struct splitter_context *sc,
86                         struct meta_word *mw,
87                         int indent)
88 {
89   int i;
90   for (i = 0; i < indent; i++) {
91     printf(" ");
92   }
93   printf("*meta word type=%s(%d-%d):score=%d:seg_class=%s",
94          anthy_metaword_type_tab[mw->type].name,
95          mw->from, mw->len, mw->score,
96          anthy_seg_class_name(mw->seg_class));
97   print_metaword_features(mw->mw_features);
98   printf(":can_use=%d*\n", mw->can_use);
99   if (mw->wl) {
100     anthy_print_word_list(sc, mw->wl);
101   }
102   if (mw->cand_hint.str) {
103     printf("(");
104     anthy_putxstr(&mw->cand_hint);
105     printf(")\n");
106   }
107   if (mw->mw1) {
108     anthy_do_print_metaword(sc, mw->mw1, indent + 1);
109   }    
110   if (mw->mw2) {
111     anthy_do_print_metaword(sc, mw->mw2, indent + 1);
112   }
113 }
114
115 void
116 anthy_print_metaword(struct splitter_context *sc,
117                      struct meta_word *mw)
118 {
119   anthy_do_print_metaword(sc, mw, 0);
120 }
121
122 static struct meta_word *
123 alloc_metaword(struct splitter_context *sc)
124 {
125   struct meta_word *mw;
126   mw = anthy_smalloc(sc->word_split_info->MwAllocator);
127   mw->type = MW_SINGLE;
128   mw->score = 0;
129   mw->struct_score = 0;
130   mw->dep_word_hash = 0;
131   mw->core_wt = anthy_wt_none;
132   mw->mw_features = 0;
133   mw->dep_class = DEP_NONE;
134   mw->wl = NULL;
135   mw->mw1 = NULL;
136   mw->mw2 = NULL;
137   mw->cand_hint.str = NULL;
138   mw->cand_hint.len = 0;
139   mw->seg_class = SEG_HEAD;
140   mw->can_use = ok;
141   return mw;
142 }
143
144
145 /*
146  * wl¤ÎÀÜƬ¼­Éôʬ¤ÈÀÜÈø¼­Éôʬ¤òʸ»úÎó¤È¤·¤Æ¼è¤ê½Ð¤¹
147  */
148 static void
149 get_surrounding_text(struct splitter_context* sc,
150                      struct word_list* wl,
151                      xstr* xs_pre, xstr* xs_post)
152 {
153     int post_len = wl->part[PART_DEPWORD].len + wl->part[PART_POSTFIX].len;
154     int pre_len = wl->part[PART_PREFIX].len;
155
156     xs_pre->str = sc->ce[wl->from].c;
157     xs_pre->len = pre_len;
158     xs_post->str = sc->ce[wl->from + wl->len - post_len].c;
159     xs_post->len = post_len;
160 }
161
162 static int
163 count_vu(xstr *xs) {
164   int i, r = 0;
165   for (i = 0; i < xs->len; i++) {
166     if (xs->str[i] == KK_VU) {
167       r++;
168     }
169   }
170   return r;
171 }
172
173 /*
174  * Ê£¹ç¸ì¤Ç¤¢¤ëwl¤«¤énÈÖ¤á¤ÎÉôʬ¤ò¼è¤ê½Ð¤·¤Æmw¤Ë¤¹¤ë
175  */
176 static struct meta_word*
177 make_compound_nth_metaword(struct splitter_context* sc, 
178                            compound_ent_t ce, int nth,
179                            struct word_list* wl,
180                            enum metaword_type type)
181 {
182   int i;
183   int len = 0;
184   int from = wl->from;
185   int seg_num = anthy_compound_get_nr_segments(ce);
186   struct meta_word* mw;
187   xstr xs_pre, xs_core, xs_post;
188
189   get_surrounding_text(sc, wl, &xs_pre, &xs_post);
190
191   for (i = 0; i <= nth; ++i) {
192     xstr part;
193     from += len;
194     len = anthy_compound_get_nth_segment_len(ce, i);
195     part.str = sc->ce[from].c;
196     part.len = len;
197     len -= count_vu(&part);
198     if (i == 0) {
199       len += xs_pre.len;
200     }
201     if (i == seg_num - 1) {
202       len += xs_post.len;
203     }
204   }
205   
206   mw = alloc_metaword(sc);
207   mw->from = from;
208   mw->len = len;
209   mw->type = type;
210   mw->score = 1000;
211   mw->seg_class = wl->seg_class;
212
213   anthy_compound_get_nth_segment_xstr(ce, nth, &xs_core);
214   if (nth == 0) {
215     anthy_xstrcat(&mw->cand_hint, &xs_pre);
216   }
217   anthy_xstrcat(&mw->cand_hint, &xs_core);
218   if (nth == seg_num - 1) {
219     anthy_xstrcat(&mw->cand_hint, &xs_post);
220   }
221   return mw;
222 }
223
224
225 /*
226  * metaword¤ò¼ÂºÝ¤Ë·ë¹ç¤¹¤ë
227  */
228 static struct meta_word *
229 anthy_do_cons_metaword(struct splitter_context *sc,
230                        enum metaword_type type,
231                        struct meta_word *mw, struct meta_word *mw2)
232 {
233   struct meta_word *n;
234  
235   n = alloc_metaword(sc);
236   n->from = mw->from;
237   n->len = mw->len + (mw2 ? mw2->len : 0);
238
239   if (mw2) {
240     n->score = sqrt(mw->score) * sqrt(mw2->score);
241   } else {
242     n->score = mw->score;
243   }
244   n->type = type;
245   n->mw1 = mw;
246   n->mw2 = mw2;
247   if (mw2) {
248     n->seg_class = mw2->seg_class;
249     n->nr_parts = mw->nr_parts + mw2->nr_parts;
250     n->dep_word_hash = mw2->dep_word_hash;
251   } else {
252     n->seg_class = mw->seg_class;
253     n->nr_parts = mw->nr_parts;
254     n->dep_word_hash = mw->dep_word_hash;
255   }
256   anthy_commit_meta_word(sc, n);
257   return n;
258 }
259
260 /*
261  * Ê£¹ç¸ìÍѤÎmeta_word¤òºîÀ®¤¹¤ë¡£
262  */
263 static void
264 make_compound_metaword(struct splitter_context* sc, struct word_list* wl)
265 {
266   int i, j;
267   seq_ent_t se = wl->part[PART_CORE].seq;
268   int ent_num = anthy_get_nr_dic_ents(se, NULL);
269
270   for (i = 0; i < ent_num; ++i) {
271     compound_ent_t ce;
272     int seg_num;
273     struct meta_word *mw = NULL;
274     struct meta_word *mw2 = NULL;
275     if (!anthy_get_nth_dic_ent_is_compound(se, i)) {
276       continue;
277     }
278     ce = anthy_get_nth_compound_ent(se, i);
279     seg_num = anthy_compound_get_nr_segments(ce);
280
281     for (j = seg_num - 1; j >= 0; --j) {
282       enum metaword_type type;
283       mw = make_compound_nth_metaword(sc, ce, j, wl, MW_COMPOUND_LEAF);
284       anthy_commit_meta_word(sc, mw);
285
286       type = j == 0 ? MW_COMPOUND_HEAD : MW_COMPOUND;
287       mw2 = anthy_do_cons_metaword(sc, type, mw, mw2);
288     }
289   }
290 }
291
292 /*
293  * Ê£¹ç¸ì¤ÎÃæ¤Î¸Ä¡¹¤ÎʸÀá¤ò·ë¹ç¤·¤¿meta_word¤òºîÀ®¤¹¤ë¡£
294  */
295 static void
296 make_compound_part_metaword(struct splitter_context* sc, struct word_list* wl)
297 {
298   int i, j, k;
299   seq_ent_t se = wl->part[PART_CORE].seq;
300   int ent_num = anthy_get_nr_dic_ents(se, NULL);
301
302   for (i = 0; i < ent_num; ++i) {
303     compound_ent_t ce;
304     int seg_num;
305     struct meta_word *mw = NULL;
306     struct meta_word *mw2 = NULL;
307
308     if (!anthy_get_nth_dic_ent_is_compound(se, i)) {
309       continue;
310     }
311
312     ce = anthy_get_nth_compound_ent(se, i);
313     seg_num = anthy_compound_get_nr_segments(ce);
314
315     /* ¸å¤í¤«¤é */
316     for (j = seg_num - 1; j >= 0; --j) {
317       mw = make_compound_nth_metaword(sc, ce, j, wl, MW_COMPOUND_PART);
318       for (k = j - 1; k >= 0; --k) {
319         mw2 = make_compound_nth_metaword(sc, ce, k, wl, MW_COMPOUND_PART);
320         mw2->len += mw->len;
321         mw2->score += mw->score;
322         anthy_xstrcat(&mw2->cand_hint, &mw->cand_hint);
323
324         anthy_commit_meta_word(sc, mw2);        
325         mw = mw2;
326       }
327     } 
328   }
329 }
330
331 /*
332  * Ã±Ê¸Àáñ¸ì
333  */
334 static void
335 make_simple_metaword(struct splitter_context *sc, struct word_list* wl)
336 {
337   struct meta_word *mw = alloc_metaword(sc);
338   mw->wl = wl;
339   mw->from = wl->from;
340   mw->len = wl->len;
341   mw->score = 1000;
342   mw->type = MW_SINGLE;
343   mw->dep_class = wl->part[PART_DEPWORD].dc;
344   mw->seg_class = wl->seg_class;
345   if (wl->part[PART_CORE].len) {
346     mw->core_wt = wl->part[PART_CORE].wt;
347   }
348   mw->nr_parts = NR_PARTS;
349   mw->dep_word_hash = wl->dep_word_hash;
350   mw->mw_features = wl->mw_features;
351   anthy_commit_meta_word(sc, mw);
352 }
353
354 /*
355  * wordlist°ì¸Ä¤«¤é¤Ê¤ë¡¢metaword¤òºîÀ®
356  */
357 static void
358 make_metaword_from_word_list(struct splitter_context *sc)
359 {
360   int i;
361   for (i = 0; i < sc->char_count; i++) {
362     struct word_list *wl;
363     for (wl = sc->word_split_info->cnode[i].wl;
364          wl; wl = wl->next) {
365       if (wl->is_compound) {
366         make_compound_part_metaword(sc, wl);
367         make_compound_metaword(sc, wl);
368       } else {
369         make_simple_metaword(sc, wl);
370       }
371     }
372   }
373 }
374
375 /*
376  * metaword¤ò¥ê¥¹¥ÈÉ÷¤Ë·ë¹ç¤¹¤ë
377  */
378 static struct meta_word *
379 list_metaword(struct splitter_context *sc,
380               enum metaword_type type,
381               struct meta_word *mw, struct meta_word *mw2)
382 {
383   struct meta_word *wrapped_mw = anthy_do_cons_metaword(sc, type, mw2, NULL);
384   struct meta_word *n = anthy_do_cons_metaword(sc, type, mw, wrapped_mw);
385
386   n->mw_features = mw->mw_features | mw2->mw_features;
387
388   return n;
389 }
390
391 /*
392  * Æ°»ìÏ¢ÍÑ·Á + ·ÁÍƻ첽ÀÜÈø¸ì ¡Ö¡Á¤·¤ä¤¹¤¤¡×¤Ê¤É
393  */
394 static void
395 try_combine_v_renyou_a(struct splitter_context *sc,
396                        struct meta_word *mw, struct meta_word *mw2)
397 {
398   wtype_t w2;
399   if (!mw->wl || !mw2->wl) return;
400
401   w2 = mw2->wl->part[PART_CORE].wt;
402
403   if (mw->wl->head_pos == POS_V &&
404       mw->wl->tail_ct == CT_RENYOU &&
405       anthy_wtype_get_pos(w2) == POS_D2KY) {
406     /* ·ÁÍÆ»ì¤Ç¤Ï¤¢¤ë¤Î¤Ç¼¡¤Î¥Á¥§¥Ã¥¯ */
407     if (anthy_get_seq_ent_wtype_freq(mw2->wl->part[PART_CORE].seq, 
408                                      anthy_wtype_a_tail_of_v_renyou)) {
409       list_metaword(sc, MW_V_RENYOU_A, mw, mw2);
410     }
411   }
412 }
413
414 /*
415  * Æ°»ìÏ¢ÍÑ·Á + Ì¾»ì²½ÀÜÈø¸ì(#D2T35) ¡ÖÆþ¤ì ¤¿¤Æ(¤Î¤ªÃã)¡×¤Ê¤É
416  */
417 static void
418 try_combine_v_renyou_noun(struct splitter_context *sc,
419                           struct meta_word *mw, struct meta_word *mw2)
420 {
421   wtype_t w2;
422   if (!mw->wl || !mw2->wl) return;
423
424   w2 = mw2->wl->part[PART_CORE].wt;
425   if (mw->wl->head_pos == POS_V &&
426       mw->wl->tail_ct == CT_RENYOU &&
427       anthy_wtype_get_pos(w2) == POS_NOUN &&
428       anthy_wtype_get_scos(w2) == SCOS_T40) {
429     list_metaword(sc, MW_V_RENYOU_NOUN, mw, mw2);
430   }
431 }
432
433 /*
434  * ¿ô»ú¤ò·ë¹ç¤¹¤ë
435  */
436 static void
437 try_combine_number(struct splitter_context *sc,
438                  struct meta_word *mw1, struct meta_word *mw2)
439 {
440   struct word_list *wl1 = mw1->wl;
441   struct word_list *wl2 = mw2->wl;
442   struct meta_word *combined_mw;
443   int recursive = wl2 ? 0 : 1; /* combined¤Êmw¤ò·ë¹ç¤¹¤ë¾ì¹ç1 */
444
445   /* º¸mw¤Ï¿ô»ì */
446
447   if (anthy_wtype_get_pos(wl1->part[PART_CORE].wt) != POS_NUMBER) return;  
448   if (recursive) {
449     /* ±¦mw¤Ï¿ô»ú¤ò·ë¹ç¤·¤¿mw */
450     if (mw2->type != MW_NUMBER) return;
451     wl2 = mw2->mw1->wl;
452   } else {
453     /* ±¦mw¤Ï¿ô»ì */
454     if (anthy_wtype_get_pos(wl2->part[PART_CORE].wt) != POS_NUMBER) return;    
455   }
456   /* º¸mw¤Î¸å¤í¤Ëʸ»ú¤¬ÉÕ¤¤¤Æ¤¤¤Ê¤±¤ì¤Ð */
457   if (wl1->part[PART_POSTFIX].len == 0 &&
458       wl1->part[PART_DEPWORD].len == 0) {
459     int scos1 = anthy_wtype_get_scos(wl1->part[PART_CORE].wt);
460     int scos2 = anthy_wtype_get_scos(wl2->part[PART_CORE].wt);
461
462     /* #NN¤ÏÂоݳ° */
463     if (scos2 == SCOS_NONE) return;
464     /* 
465        º¸mw¤Î¼ïÎà¤Ë¤è¤Ã¤Æ¡¢¸å¤í¤Ë¤Ä¤¯¤³¤È¤¬¤Ç¤­¤ë±¦mw¤Î¼ïÎबÊѤï¤ë
466        Î㤨¤Ð°ì¡Á¶å¤Î¸å¤í¤Ë¤ÏËü¡Á¶åËü¡¢²¯¡Á¶å²¯¤·¤«¤Ä¤¯¤³¤È¤¬¤Ç¤­¤Ê¤¤¤¬¡¢
467        ½½¡Á¶å½½¤Î¸å¤í¤Ë¤Ï¡¢¤¢¤ï¤»¤Æ°ì¡Á¶å¤Ê¤É¤â¤Ä¤¯¤³¤È¤¬¤Ç¤­¤ë
468      */
469     switch (scos1) {
470     case SCOS_N1: 
471       if (scos2 == SCOS_N1) return; /* ¸å¤í¤Ë°ì¡Á¶å¤¬¤Ä¤¤¤Æ¤Ï¤¤¤±¤Ê¤¤ */
472     case SCOS_N10:
473       if (scos2 == SCOS_N10) return; /* ¸å¤í¤Ë½½¡Á¶å½½¤¬¤Ä¤¤¤Æ¤Ï¤¤¤±¤Ê¤¤ */
474     case SCOS_N100:
475       if (scos2 == SCOS_N100) return; /* ¸å¤í¤ËÉ´¡Á¶åÉ´¤¬¤Ä¤¤¤Æ¤Ï¤¤¤±¤Ê¤¤ */
476     case SCOS_N1000:
477       if (scos2 == SCOS_N1000) return; /* ¸å¤í¤ËÀé¡Á¶åÀ餬¤Ä¤¤¤Æ¤Ï¤¤¤±¤Ê¤¤ */
478     case SCOS_N10000:
479       /* Ëü¡Á¶åËü¡¢²¯¡Á¶å²¯¡Ä¤Ê¤É¤Ï¡¢
480          ¤¤¤Ä¤Ç¤â¸å¤í¤Ë¤Ä¤¯¤³¤È¤¬¤Ç¤­¤ë */
481       break;
482     default:
483       return;
484     }
485
486     if (recursive) {
487       combined_mw = anthy_do_cons_metaword(sc, MW_NUMBER, mw1, mw2);
488     } else {
489       /* ½é¤á¤Æ·ë¹ç¤¹¤ë¾ì¹ç¤Ï¸å¤í¤Ënull¤ò¤Ä¤±¤Ælist¤Ë¤¹¤ë */
490       combined_mw = list_metaword(sc, MW_NUMBER, mw1, mw2);
491     }
492     combine_metaword(sc, combined_mw);
493   }
494 }
495
496 /* ±¦ÎÙ¤Îmetaword¤È·ë¹ç¤Ç¤­¤ë¤«¥Á¥§¥Ã¥¯ */
497 static void
498 try_combine_metaword(struct splitter_context *sc,
499                      struct meta_word *mw1, struct meta_word *mw2)
500 {
501   if (!mw1->wl) return;
502
503   /* metaword¤Î·ë¹ç¤ò¹Ô¤¦¤¿¤á¤Ë¤Ï¡¢¸å³¤Î
504      metaword¤ËÀÜƬ¼­¤¬¤Ê¤¤¤³¤È¤¬É¬Í× */
505   if (mw2->wl && mw2->wl->part[PART_PREFIX].len > 0) {
506     return;
507   }
508   
509   try_combine_v_renyou_a(sc, mw1, mw2);
510   try_combine_v_renyou_noun(sc, mw1, mw2);
511   try_combine_number(sc, mw1, mw2);
512 }
513
514 static void
515 combine_metaword(struct splitter_context *sc, struct meta_word *mw)
516 {
517   struct word_split_info_cache *info = sc->word_split_info;
518   int i;
519
520   if (mw->mw_features & MW_FEATURE_DEP_ONLY) {
521     /* ÉÕ°¸ì¤À¤±¤ÎʸÀá¤È¤Ï·ë¹ç¤·¤Ê¤¤ */  
522     return;
523   }
524
525   for (i = mw->from - 1; i >= 0; i--) {
526     struct meta_word *mw_left;
527     for (mw_left = info->cnode[i].mw; mw_left; mw_left = mw_left->next) {
528       if (mw_left->from + mw_left->len == mw->from) {
529         /* ·ë¹ç¤Ç¤­¤ë¤«¥Á¥§¥Ã¥¯ */
530         try_combine_metaword(sc, mw_left, mw);
531       }
532     }
533   }
534 }
535
536 static void
537 combine_metaword_all(struct splitter_context *sc)
538 {
539   int i;
540
541   struct word_split_info_cache *info = sc->word_split_info;
542   /* metaword¤Îº¸Ã¼¤Ë¤è¤ë¥ë¡¼¥× */
543   for (i = sc->char_count - 1; i >= 0; i--){
544     struct meta_word *mw;
545     /* ³Æmetaword¤Î¥ë¡¼¥× */
546     for (mw = info->cnode[i].mw;
547          mw; mw = mw->next) {
548       combine_metaword(sc, mw);
549     }
550   }
551 }
552
553 static void
554 make_dummy_metaword(struct splitter_context *sc, int from,
555                     int len, int orig_len)
556 {
557   int score = 0;
558   struct meta_word *mw, *n;
559
560   for (mw = sc->word_split_info->cnode[from].mw; mw; mw = mw->next) {
561    if (mw->len != orig_len) continue;
562     if (mw->score > score) {
563       score = mw->score;
564     }
565   }
566
567   n = alloc_metaword(sc);
568   n->type = MW_DUMMY;
569   n->from = from;
570   n->len = len;
571   n->score = 3 * score * len / orig_len;
572   if (mw) {
573     mw->nr_parts = 0;
574   }
575   anthy_commit_meta_word(sc, n);
576 }
577
578 /*
579  * Ê¸Àá¤ò¿­¤Ð¤·¤¿¤é¤½¤ì¤ò³Ð¤¨¤Æ¤ª¤¯
580  */
581 static void
582 make_expanded_metaword_all(struct splitter_context *sc)
583 {
584   int i, j;
585   if (anthy_select_section("EXPANDPAIR", 0) == -1) {
586     return ;
587   }
588   for (i = 0; i < sc->char_count; i++) {
589     for (j = 1; j < sc->char_count - i; j++) {
590       /* Á´¤Æ¤ÎÉôʬʸ»úÎó¤ËÂФ·¤Æ */
591       xstr xs;
592       xs.len = j;
593       xs.str = sc->ce[i].c;
594       if (anthy_select_row(&xs, 0) == 0) {
595         /* ¤³¤ÎÉôʬʸ»úÎó¤Ï²áµî¤Ë³ÈÂç¤ÎÂоݤȤʤä¿ */
596         int k;
597         int nr = anthy_get_nr_values();
598         for (k = 0; k < nr; k++) {
599           xstr *exs;
600           exs = anthy_get_nth_xstr(k);
601           if (exs && exs->len <= sc->char_count - i) {
602             xstr txs;
603             txs.str = sc->ce[i].c;
604             txs.len = exs->len;
605             if (!anthy_xstrcmp(&txs, exs)) {
606               make_dummy_metaword(sc, i, txs.len, j);
607             }
608           }
609         }
610       }
611     }
612   }
613 }
614
615 /* ¤ªÃãÆþ¤ì³Ø½¬¤Îmetaword¤òºî¤ë */
616 static void
617 make_ochaire_metaword(struct splitter_context *sc,
618                       int from, int len)
619 {
620   struct meta_word *mw;
621   int count;
622   int s;
623   int j;
624   int seg_len;
625   int mw_len = 0;
626   xstr* xs;
627
628   (void)len;
629
630   /* Ê¸Àá¿ô¤ò¼èÆÀ */
631   count = anthy_get_nth_value(0);
632   /* °ìÈÖ±¦¤ÎʸÀá¤ò¤Î¤¾¤¤¤¿Ê¸»ú¿ô¤Î¹ç·×¤ò·×»» */
633   for (s = 0, j = 0; j < count - 1; j++) {
634     s += anthy_get_nth_value(j * 2 + 1);
635   }
636   /* °ìÈÖ±¦¤ÎʸÀá¤Îmetaword¤ò¹½À® */
637   xs = anthy_get_nth_xstr((count - 1) * 2 + 2);
638   if (!xs) {
639     return ;
640   }
641   seg_len = anthy_get_nth_value((count - 1) * 2 + 1);
642   mw = alloc_metaword(sc);
643   mw->type = MW_OCHAIRE;
644   mw->from = from + s;
645   mw->len = seg_len;
646   mw->score = OCHAIRE_SCORE;
647   mw->cand_hint.str = malloc(sizeof(xchar)*xs->len);
648   anthy_xstrcpy(&mw->cand_hint, xs);
649   anthy_commit_meta_word(sc, mw);
650   mw_len += seg_len;
651   /* ¤½¤ì°Ê³°¤ÎʸÀá¤Çmetaword¤ò¹½À® */
652   for (j-- ; j >= 0; j--) {
653     struct meta_word *n;
654     seg_len = anthy_get_nth_value(j * 2 + 1);
655     s -= seg_len;
656     xs = anthy_get_nth_xstr(j * 2 + 2);
657     if (!xs) {
658       return ;
659     }
660     n = alloc_metaword(sc);
661     n->type = MW_OCHAIRE;
662     /* ±¦¤Îmetaword¤ò¤Ä¤Ê¤° */
663     n->mw1 = mw;
664     n->from = from + s;
665     n->len = seg_len;
666     n->score = OCHAIRE_SCORE;
667     n->cand_hint.str = malloc(sizeof(xchar)*xs->len);
668     anthy_xstrcpy(&n->cand_hint, xs);
669     anthy_commit_meta_word(sc, n);
670     mw = n;
671     mw_len += seg_len;
672   } 
673 }
674
675 /*
676  * Ê£¿ô¤ÎʸÀá¤ÎÁȤòÍúÎò¤«¤é¸¡º÷¤¹¤ë
677  */
678 static void
679 make_ochaire_metaword_all(struct splitter_context *sc)
680 {
681   int i;
682   if (anthy_select_section("OCHAIRE", 0) == -1) {
683     return ;
684   }
685
686   for (i = 0; i < sc->char_count; i++) {
687     xstr xs;
688     xs.len = sc->char_count - i;
689     xs.str = sc->ce[i].c;
690     if (anthy_select_longest_row(&xs) == 0) {
691       xstr* key;
692       int len;
693       anthy_mark_row_used();
694       key = anthy_get_index_xstr();
695       len = key->len;
696
697       make_ochaire_metaword(sc, i, len);
698       /* º£²ó¸«¤Ä¤«¤Ã¤¿ meta_word ¤Î¼¡¤Îʸ»ú¤«¤é»Ï¤á¤ë */
699       i += len - 1;
700       break;
701     }
702   }
703 }
704
705 static void
706 add_dummy_metaword(struct splitter_context *sc,
707                    int from)
708 {
709   struct meta_word *n;
710   n = alloc_metaword(sc);
711   n->from = from;
712   n->len = 1;
713   n->type = MW_SINGLE;
714   n->score = 1;
715   n->seg_class = SEG_BUNSETSU;
716   anthy_commit_meta_word(sc, n);
717 }
718
719 /* »ØÄꤷ¤¿metaword¤òwrap¤·¤Æjʸ»úŤ¤meta_word¤òºî¤ë */
720 static void
721 expand_meta_word(struct splitter_context *sc,
722                  struct meta_word *mw, int from, int len,
723                  int destroy_seg_class, int j)
724 {
725   struct meta_word *n;
726   n = alloc_metaword(sc);
727   n->from = from;
728   n->len = len + j;
729   if (mw) {
730     n->type = MW_WRAP;
731     n->mw1 = mw;
732     n->score = mw->score;
733     n->nr_parts = mw->nr_parts;
734     if (destroy_seg_class) {
735       n->seg_class = SEG_BUNSETSU;
736       n->score /= 10;
737     } else {
738       n->seg_class = mw->seg_class;
739     }
740   } else {
741     n->type = MW_SINGLE;
742     n->score = 1;
743     n->seg_class = SEG_BUNSETSU;
744   }
745   anthy_commit_meta_word(sc, n);
746 }
747
748 /*
749  * metaword¤Î¸å¤í¤Î»¨Â¿¤Êʸ»ú¤ò¤¯¤Ã¤Ä¤±¤¿metaword¤ò¹½À®¤¹¤ë
750  */
751 static void
752 make_metaword_with_depchar(struct splitter_context *sc,
753                            struct meta_word *mw)
754 {
755   int j;
756   int destroy_seg_class = 0;
757   int from = mw ? mw->from : 0;
758   int len = mw ? mw->len : 0;
759
760   /* metaword¤Îľ¸å¤Îʸ»ú¤Î¼ïÎà¤òÄ´¤Ù¤ë */
761   int type;
762   if (sc->char_count <= from + len) {
763     return ;
764   }
765   type = anthy_get_xchar_type(*sc->ce[from + len].c);
766   if (!(type & XCT_SYMBOL) &&
767       !(type & XCT_PART)) {
768     return;
769   }
770   if (type & XCT_PUNCTUATION) {
771     /* ¶çÆÉÅÀ¤Ê¤é¤ÐÊ̤ÎʸÀá¤Ë¤¹¤ë */
772     return ;
773   }
774
775   /* Æ±¤¸¼ïÎà¤Îʸ»ú¤Ç¤Ê¤±¤ì¤Ð¤¯¤Ã¤Ä¤±¤ë¤Î¤ò¤¦¤Á¤­¤ê */
776   for (j = 0; from + len + j < sc->char_count; j++) {
777     int p = from + len + j;
778     if ((anthy_get_xchar_type(*sc->ce[p].c) != type)) {
779       break;
780     }
781     if (!(p + 1 < sc->char_count) ||
782         *sc->ce[p].c != *sc->ce[p + 1].c) {
783       destroy_seg_class = 1;
784     }
785   }
786
787   /* ¾å¤Î¥ë¡¼¥×¤òÈ´¤±¤¿»þ¡¢j¤Ë¤ÏÆÈΩ¤Ç¤­¤Ê¤¤Ê¸»ú¤Î¿ô¤¬Æþ¤Ã¤Æ¤¤¤ë */
788
789   /* ÆÈΩ¤Ç¤­¤Ê¤¤Ê¸»ú¤¬¤¢¤ë¤Î¤Ç¡¢¤½¤ì¤òÉÕ¤±¤¿metaword¤òºî¤ë */
790   if (j > 0) {
791     expand_meta_word(sc, mw, from, len, destroy_seg_class, j);
792   }
793 }
794
795 static void 
796 make_metaword_with_depchar_all(struct splitter_context *sc)
797 {
798   int i;
799   struct word_split_info_cache *info = sc->word_split_info;
800
801   /* Á´metaword¤ËÂФ·¤Æ */
802   for (i = 0; i < sc->char_count; i++) {
803     struct meta_word *mw;
804     for (mw = info->cnode[i].mw;
805          mw; mw = mw->next) {
806       make_metaword_with_depchar(sc, mw);
807     }
808     if (!info->cnode[i].mw) {
809       /**/
810       add_dummy_metaword(sc, i);
811     }
812   }
813   /* Ê¸¤Îº¸Ã¼¤«¤é»Ï¤Þ¤ë¤â¤Î */
814   make_metaword_with_depchar(sc, NULL);
815 }
816
817 static int
818 is_single(xstr* xs)
819 {
820   int i;
821   int xct;
822   for (i = xs->len - 1; i >= 1; --i) {
823     xct = anthy_get_xchar_type(xs->str[i]);
824     if (!(xct & XCT_PART)) {
825       return 0;
826     }
827   }
828   return 1;
829 }
830
831 static void 
832 bias_to_single_char_metaword(struct splitter_context *sc)
833 {
834   int i;
835
836   for (i = sc->char_count - 1; i >= 0; --i) {
837     struct meta_word *mw;
838     xstr xs;
839     int xct;
840
841     struct char_node *cnode = &sc->word_split_info->cnode[i];
842
843     /* ¥«¥Ã¥³¤Î¾ì¹ç¤Ï°ìʸ»ú¤ÇʸÀá¤ò¹½À®¤Ç¤­¤ë */
844     xct = anthy_get_xchar_type(*sc->ce[i].c);
845     if (xct & (XCT_OPEN|XCT_CLOSE)) {
846       continue;
847     }
848
849     xs.str = sc->ce[i].c;
850     for (mw = cnode->mw; mw; mw = mw->next) {
851       /* ÉÕ°¸ì¤Î¤ß¤ÎʸÀá¤Ï¸ºÅÀ¤·¤Ê¤¤ */
852       if (mw->mw_features & MW_FEATURE_DEP_ONLY) {
853         continue;
854       } 
855       /* °ìʸ»ú(+ľÁ°¤Ë¤Ä¤Ê¤¬¤ëʸ»ú¤Î·«¤êÊÖ¤·)¤Î¥¹¥³¥¢¤ò²¼¤²¤ë */
856       xs.len = mw->len;
857       if (is_single(&xs)) {
858         mw->score /= 10;
859       }
860     }
861   }
862 }
863
864 void
865 anthy_mark_border_by_metaword(struct splitter_context* sc,
866                               struct meta_word* mw)
867 {
868   struct word_split_info_cache* info = sc->word_split_info;
869   if (!mw) return;
870
871   switch (mw->type) {
872   case MW_DUMMY:
873     /* BREAK THROUGH */
874   case MW_SINGLE:
875     /* BREAK THROUGH */
876   case MW_COMPOUND_PART: 
877     info->seg_border[mw->from] = 1;    
878     break;
879   case MW_COMPOUND_LEAF:
880     info->seg_border[mw->from] = 1;    
881     info->best_mw[mw->from] = mw;
882     mw->can_use = ok;
883     break;
884   case MW_COMPOUND_HEAD:
885     /* BREAK THROUGH */
886   case MW_COMPOUND:
887     /* BREAK THROUGH */
888   case MW_NUMBER:
889     info->best_mw[mw->mw1->from] = mw->mw1;
890     anthy_mark_border_by_metaword(sc, mw->mw1);
891     anthy_mark_border_by_metaword(sc, mw->mw2);
892     break;
893   case MW_V_RENYOU_A:
894     /* BREAK THROUGH */
895   case MW_V_RENYOU_NOUN:
896     info->seg_border[mw->from] = 1;    
897     break;
898   case MW_WRAP:
899     anthy_mark_border_by_metaword(sc, mw->mw1);
900     break;
901   case MW_OCHAIRE:
902     info->seg_border[mw->from] = 1;
903     anthy_mark_border_by_metaword(sc, mw->mw1);
904     break;
905   default:
906     break;
907   }
908 }
909
910 void
911 anthy_make_metaword_all(struct splitter_context *sc)
912 {
913   /* ¤Þ¤º¡¢word_list°ì¸Ä¤Îmetaword¤òºî¤ë */
914   make_metaword_from_word_list(sc);
915
916   /* metaword¤ò·ë¹ç¤¹¤ë */
917   combine_metaword_all(sc);
918
919   /* ³ÈÂ礵¤ì¤¿Ê¸Àá¤ò½èÍý¤¹¤ë */
920   make_expanded_metaword_all(sc);
921
922   /* ÂùÅÀ¤äĹ²»¤Ê¤É¤Îµ­¹æ¡¢¤½¤Î¾¤Îµ­¹æ¤ò½èÍý */
923   make_metaword_with_depchar_all(sc);
924
925   /* ¤ª¤Á¤ã¤ò¤¤¤ì¤ë */
926   make_ochaire_metaword_all(sc);
927
928   /* °ìʸ»ú¤ÎʸÀá¤Ï¸ºÅÀ */
929   bias_to_single_char_metaword(sc);
930 }
931
932 /* 
933  * »ØÄꤵ¤ì¤¿Îΰè¤ò¥«¥Ð¡¼¤¹¤ëmetaword¤ò¿ô¤¨¤ë 
934  */
935 int
936 anthy_get_nr_metaword(struct splitter_context *sc,
937                      int from, int len)
938 {
939   struct meta_word *mw;
940   int n;
941
942   for (n = 0, mw = sc->word_split_info->cnode[from].mw;
943        mw; mw = mw->next) {
944     if (mw->len == len && mw->can_use == ok) {
945       n++;
946     }
947   }
948   return n;
949 }
950
951 struct meta_word *
952 anthy_get_nth_metaword(struct splitter_context *sc,
953                       int from, int len, int nth)
954 {
955   struct meta_word *mw;
956   int n;
957   for (n = 0, mw = sc->word_split_info->cnode[from].mw;
958        mw; mw = mw->next) {
959     if (mw->len == len && mw->can_use == ok) {
960       if (n == nth) {
961         return mw;
962       }
963       n++;
964     }
965   }
966   return NULL;
967 }