OSDN Git Service

*** empty log message ***
[chasen-legacy/chasen.git] / lib / chalib.c
1 /*
2  * Copyright (c) 2003 Nara Institute of Science and Technology
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name Nara Institute of Science and Technology may not be used to
15  *    endorse or promote products derived from this software without
16  *    specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY Nara Institute of Science and Technology 
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
21  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE Nara Institute
22  * of Science and Technology BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * $Id: chalib.c,v 1.3 2007/03/25 11:57:27 kazuma-t Exp $
31  */
32
33 #include "chalib.h"
34 #include "dartsdic.h"
35 #include "literal.h"
36 #include "tokenizer.h"
37
38 #define CHA_NAME       "ChaSen"
39
40 #define STR_UNSPECIFIED "UNSPEC"
41 #define STR_ANNOTATION "ANNO"
42
43 darts_t *Da_dicfile[DIC_NUM];
44 int Da_ndicfile = 0;
45
46 int Cha_cost_width = -1;
47 enum cha_lang Cha_lang = CHASEN_LANG_JA;
48 #if defined _WIN32
49 enum cha_encode Cha_encode = CHASEN_ENCODE_SJIS;
50 #else
51 enum cha_encode Cha_encode = CHASEN_ENCODE_EUCJP;
52 #endif
53
54 static int cost_width0;
55
56 static char dadic_filename[DIC_NUM][PATH_MAX];
57
58 static int opt_show = 'b', opt_form = 'f', opt_ja, opt_cmd;
59 static char *opt_form_string;
60
61 /*
62  *  cha_version()
63  */
64 void
65 cha_version(FILE * fp)
66 {
67     if (!fp)
68         return;
69
70     fprintf(fp,
71             "%s version %s (c) 1996-2007 Nara Institute of Science and Technology\n",
72             CHA_NAME, VERSION);
73     fprintf(fp, "Grammar files are in ChaSen's new v-gram format.\n");
74 }
75
76 /*
77  * cha_set_opt_form()
78  */
79 void
80 cha_set_opt_form(char *format)
81 {
82     char *f;
83
84     /*
85      * -[fecdv] 
86      */
87     if (format &&
88         format[0] == '-' && strchr("fecdv", format[1])
89         && format[2] == '\0') {
90         opt_form = format[1];
91         format = NULL;
92     }
93
94     if (format == NULL) {
95         if (opt_form == 'd' || opt_form == 'v')
96             opt_show = 'm';
97         switch (opt_form) {
98         case 'd':
99             opt_form_string =
100                 "morph(%pi,%ps,%pe,%pc,'%m','%U(%y)','%M',%U(%P'),NIL,%T0,%F0,'%I0',%c,[%ppc,],[%ppi,])";
101             break;
102         case 'v':
103             opt_form_string =
104                 "%pb%3pi %3ps %3pe %5pc %m\t%U(%y)\t%U(%a)\t%M\t%U(%P-) NIL %T0 %F0 %I0 %c %ppi, %ppc,\n";
105             break;
106         case 'f':
107             opt_form_string = "%m\t%y\t%M\t%U(%P-)\t%T \t%F \n";
108             break;
109         case 'e':
110             opt_form_string = "%m\t%U(%y)\t%M\t%P- %h %T* %t %F* %f\n";
111             break;
112         case 'c':
113             opt_form_string = "%m\t%y\t%M\t%h %t %f\n";
114             break;
115         }
116         return;
117     }
118
119     /*
120      * format string 
121      */
122     opt_form_string = format;
123     /*
124      * opt_form_string = cha_convert_escape(cha_strdup(format), 1); 
125      */
126
127     f = opt_form_string + strlen(opt_form_string);
128     if (f[-1] == '\n')
129         opt_form = 'F';
130     else
131         opt_form = 'W';
132 }
133
134 /*
135  * cha_set_language()
136  */
137 void
138 cha_set_language(char *langstr)
139 {
140     Cha_lang = CHASEN_LANG_JA;
141
142     if (langstr[0] == 'j') {
143         Cha_lang = CHASEN_LANG_JA;
144     } else if (langstr[0] == 'e') {
145         Cha_lang = CHASEN_LANG_EN;
146     }
147 }
148
149 /*
150  * cha_set_cost_width()
151  */
152 void
153 cha_set_cost_width(int cw)
154 {
155     cost_width0 = cw * MRPH_DEFAULT_WEIGHT;
156
157     /*
158      * ºÇŬ²ò°Ê³°¤âɽ¼¨¤¹¤ë¤È¤­¤Ï Cha_cost_width ¤òÀ¸¤«¤¹ 
159      */
160     Cha_cost_width = opt_show == 'b' ? -1 : cost_width0;
161 }
162
163 /*
164  * chasen_getopt_argv - initialize and read options
165  *
166  * return value:
167  *   0 - ok
168  *   1 - error
169  */
170 int
171 chasen_getopt_argv(char **argv, FILE * fp)
172 {
173     int c;
174
175     /*
176      * read -r option 
177      */
178     Cha_optind = 0;
179     while ((c = cha_getopt_chasen(argv, fp)) != EOF) {
180         switch (c) {
181         case 'i':
182             cha_set_encode(Cha_optarg);
183             break;
184         case 'r':
185             /*
186              * chasenrc file 
187              */
188             cha_set_rcpath(Cha_optarg);
189             break;
190         case '?':
191             return 1;
192         }
193     }
194
195     /*
196      * initialize if not done 
197      */
198     if (!Cha_undef_info_num)
199         cha_init();
200
201     /*
202      * read options 
203      */
204     Cha_optind = 0;
205     while ((c = cha_getopt_chasen(argv, fp)) != EOF) {
206         switch (c) {
207         case 'b':
208         case 'm':
209         case 'p':
210             opt_show = c;
211             break;
212         case 'd':
213         case 'v':
214         case 'f':
215         case 'e':
216         case 'c':
217             opt_form = c;
218             cha_set_opt_form(NULL);
219             break;
220         case 'F':
221             cha_set_opt_form(cha_convert_escape
222                              (cha_strdup(Cha_optarg), 0));
223             break;
224         case 'L':
225             cha_set_language(Cha_optarg);
226             break;
227         case 'w':               /* ¥³¥¹¥ÈÉý¤Î»ØÄê */
228             cha_set_cost_width(atoi(Cha_optarg));
229             break;
230         case 'O':
231             Cha_output_iscompound = *Cha_optarg == 'c';
232             break;
233         case 'l':
234             cha_set_output(stdout);
235             switch (*Cha_optarg) {
236             case 'p':
237                 /*
238                  * display the list of Cha_hinsi table 
239                  */
240                 cha_print_hinsi_table();
241                 exit(0);
242                 break;
243             case 't':
244                 cha_print_ctype_table();
245                 exit(0);
246                 break;
247             case 'f':
248                 cha_print_cform_table();
249                 exit(0);
250                 break;
251             default:
252                 break;
253             }
254             break;
255         case 'j':
256             opt_ja = 1;
257             break;
258         case 'C':
259             opt_cmd = 1;
260             break;
261 #if 0                           /* not necessary */
262         case '?':
263             return 1;
264 #endif
265         }
266     }
267
268     /*
269      * ºÇŬ²ò°Ê³°¤âɽ¼¨¤¹¤ë¤È¤­¤Ï Cha_cost_width ¤òÀ¸¤«¤¹ 
270      */
271     Cha_cost_width = opt_show == 'b' ? -1 : cost_width0;
272
273     return 0;
274 }
275
276 /*
277  * parse a string and output to fp or str
278  *
279  * return value:
280  *     0 - ok / no result / too many morphs
281  *     1 - quit
282  */
283 static int
284 chasen_sparse_main(char *input, FILE *output)
285 {
286     char *crlf;
287     cha_lat_t lat;
288     cha_seg_t seg;
289     /*
290      * initialize if not done 
291      */
292     if (!Cha_undef_info_num)
293         cha_init();
294     if (!opt_form_string)
295         cha_set_opt_form(NULL);
296
297     cha_set_output(output);
298
299     if (input[0] == '\0') {
300         cha_print_bos_eos(opt_form);
301         return 0;
302     }
303
304     /*
305      * parse a sentence and print 
306      */
307     while (*input) {
308         int c = 0, len, cursor;
309         if ((crlf = strpbrk(input, "\r\n")) == NULL)
310             len = strlen(input);
311         else {
312             len = crlf - input;
313             c = *crlf;
314             *crlf = '\0';
315         }
316         cha_print_reset();
317
318         cursor = 0;
319         cha_parse_bos(&lat);
320         while (cursor < len) {
321             seg.text = input + cursor;
322             seg.anno_no = -1;
323             seg.len = cha_tok_parse(Cha_tokenizer, seg.text, seg.char_type,
324                                     len - cursor, &seg.anno_no);
325             if (seg.anno_no >= 0)
326                 seg.type = SEGTYPE_ANNOTATION;
327             else
328                 seg.type = SEGTYPE_NORMAL;
329             cha_parse_segment(&lat, &seg);
330             cursor += seg.len;
331         }
332         cha_parse_eos(&lat);
333         cha_print_path(&lat, opt_show, opt_form, opt_form_string);
334
335         if (crlf == NULL)
336             break;
337         if (c == '\r' && crlf[1] == '\n')
338             input = crlf + 2;
339         else
340             input = crlf + 1;
341     }
342
343     return 0;
344 }
345
346 /*
347  * read from file/str, parse, and write to file
348  * 
349  * return value:
350  *     0 - ok / no result / too many morphs
351  *     1 - quit / eof
352  */
353 /*
354  * file -> file
355  */
356 int
357 chasen_fparse(FILE * fp_in, FILE * fp_out)
358 {
359     char line[CHA_INPUT_SIZE];
360
361     if (cha_fgets(line, sizeof(line), fp_in) == NULL)
362         return 1;
363
364     return chasen_sparse_main(line, fp_out);
365 }
366 /*
367  * string -> file
368  */
369 int
370 chasen_sparse(char *str_in, FILE * fp_out)
371 {
372     int rc;
373     char *euc_str;
374
375     euc_str = cha_malloc(strlen(str_in) + 1);
376     cha_jistoeuc(str_in, euc_str);
377     rc = chasen_sparse_main(euc_str, fp_out);
378     free(euc_str);
379
380     return rc;
381 }
382
383 static int
384 set_normal(cha_seg_t *seg)
385 {
386     seg->type = SEGTYPE_NORMAL;
387     cha_tok_parse(Cha_tokenizer, seg->text, seg->char_type,
388                   seg->len, NULL);
389
390     return seg->len;
391 }
392
393 static int
394 seg_tokenize(unsigned char *line, cha_seg_t *seg)
395 {
396     int len;
397     int i;
398
399     len = 0;
400     seg->text = line;
401     while (line[len] != '\t' && line[len] != '\0')
402         len++;
403     seg->len = len;
404     seg->posid = seg->inf_type = seg->inf_form = 0;
405
406     if (line[len] == '\0')
407         return set_normal(seg);
408
409     /* skip reading and base form */
410     for (i = 0; i < 2; i++) {
411         len++;
412         while (line[len] != '\t' && line[len] != '\0')
413             len++;
414         if (line[len] == '\0')
415             return set_normal(seg);
416     }
417
418     line += len + 1;
419     if (strcmp(line, STR_UNSPECIFIED) == 0) {
420         seg->type = SEGTYPE_UNSPECIFIED;
421         seg->char_type[0] = seg->len;
422     } else if (strcmp(line, STR_ANNOTATION) == 0) {
423         seg->type = SEGTYPE_ANNOTATION;
424         cha_tok_parse(Cha_tokenizer, seg->text, seg->char_type,
425                       seg->len, &seg->anno_no);
426         seg->char_type[0] = seg->len;
427     } else { /* read POS */
428         char *pos[256], *itype;
429         char *l = line;
430
431         seg->type = SEGTYPE_MORPH;
432         seg->char_type[0] = seg->len;
433         if ((l = strchr(l, '\t')) != NULL) {
434             *l++ = '\0';
435             itype = l;
436             if ((l = strchr(l, '\t')) != NULL) {
437                 *l++ = '\0';
438                 seg->inf_type = cha_get_type_id(itype);
439                 seg->inf_form = cha_get_form_id(l, seg->inf_type);
440             } else {
441                 fprintf(stderr, "invalid format: %s\n", line);
442                 return -1;
443             }
444         }
445         i = 0;
446         pos[i++] = l = line;
447         while ((l = strchr(l, '-')) != NULL) {
448             *l++ = '\0';
449             pos[i++] = l;
450         }
451         pos[i] = NULL;
452         if (cha_litmatch(pos[0], 3, STR_UNKNOWN_WORD,
453                          STR_UNKNOWN_WORD1, STR_UNKNOWN_WORD2))
454             seg->is_undef = 1;
455         else {
456             seg->is_undef = 0;
457             seg->posid = cha_get_nhinsi_str_id(pos);
458         }
459     }
460     
461     return seg->len;
462 }
463
464 static int
465 strip(unsigned char *s)
466 {
467     int len = strlen(s);
468
469     if (s[len - 1] == '\n')
470         s[len-- - 1] = '\0';
471
472     while (len > 0 && s[len - 1] == '\t')
473         s[len-- - 1] = '\0';
474
475     return len;
476 }
477
478
479 int
480 chasen_parse_segments(FILE *input, FILE *output)
481 {
482     cha_lat_t lat;
483     unsigned char buf[CHA_INPUT_SIZE]; /* XXX */
484     cha_seg_t seg;
485     int is_eos = 1;
486
487     if (!Cha_undef_info_num)
488         cha_init();
489     if (!opt_form_string)
490         cha_set_opt_form(NULL);
491
492     cha_set_output(output);
493
494     while (fgets(buf, CHA_INPUT_SIZE, input) != NULL) {
495         strip(buf);
496         if (is_eos) {
497             cha_print_reset();
498             cha_parse_bos(&lat);
499             is_eos = 0;
500         }
501         if (!buf[0] || cha_litmatch(buf, 2, STR_EOS, STR_BOS_EOS)) {
502             /* EOS */
503             cha_parse_eos(&lat);
504             cha_print_path(&lat, opt_show, opt_form, opt_form_string);
505             is_eos = 1;
506             continue;
507         }
508         if (seg_tokenize(buf, &seg) < 0) {
509             fprintf(stderr, "invalid format: %s\n", buf);
510             continue;
511         }
512         cha_parse_segment(&lat, &seg);
513     }
514     if (!is_eos) {
515         cha_parse_eos(&lat);
516         cha_print_path(&lat, opt_show, opt_form, opt_form_string);
517     }
518
519     return lat.len;
520 }
521
522 /*
523  * read from file/str, parse, and output to string
524  * 
525  * return value: string
526  *     !NULL - ok / no result / too many morphs
527  *     NULL - quit / eof
528  */
529
530 /*
531  * file -> string
532  */
533 char *
534 chasen_fparse_tostr(FILE * fp_in)
535 {
536     char line[CHA_INPUT_SIZE];
537
538     if (cha_fgets(line, sizeof(line), fp_in) == NULL)
539         return NULL;
540
541     if (chasen_sparse_main(line, NULL))
542         return NULL;
543
544     return cha_get_output();
545 }
546
547 /*
548  * string -> string
549  */
550 char *
551 chasen_sparse_tostr(char *str_in)
552 {
553     char *euc_str;
554
555     euc_str = cha_malloc(strlen(str_in) + 1);
556     cha_jistoeuc(str_in, euc_str);
557
558     if (chasen_sparse_main(euc_str, NULL))
559         return NULL;
560
561     free(euc_str);
562
563     return cha_get_output();
564 }
565
566 char *
567 cha_fgets(char *s, int n, FILE * fp)
568 {
569     if (opt_ja)
570         return cha_jfgets(s, n, fp);
571     else
572         return cha_fget_line(s, n, fp);
573 }
574
575 static void
576 set_dic_filename(char *filename, size_t len, char *s)
577 {
578 #ifdef PATHTYPE_MSDOS
579     if (*s == PATH_DELIMITER || *s && s[1] == ':')
580         strncpy(filename, s, len);
581 #else
582     if (*s == PATH_DELIMITER)
583         strncpy(filename, s, len);
584 #endif /* PATHTYPE_MSDOS */
585     else
586         snprintf(filename, len, "%s%s", cha_get_grammar_dir(), s);
587 }
588
589 void
590 cha_read_dadic(chasen_cell_t * cell)
591 {
592     int num;
593     char da_filename[PATH_MAX];
594     char lex_filename[PATH_MAX];
595     char dat_filename[PATH_MAX];
596
597     if (dadic_filename[0][0])
598         return;
599
600     for (num = 0; !nullp(cell); num++, cell = cha_cdr(cell)) {
601         if (num >= DIC_NUM)
602             cha_exit_file(1, "too many Darts dictionary files");
603         set_dic_filename(dadic_filename[num], PATH_MAX,
604                          cha_s_atom(cha_car(cell)));
605
606         snprintf(da_filename, PATH_MAX, "%s.da", dadic_filename[num]);
607         snprintf(lex_filename, PATH_MAX, "%s.lex", dadic_filename[num]);
608         snprintf(dat_filename, PATH_MAX, "%s.dat", dadic_filename[num]);
609         Da_dicfile[num] = da_open(da_filename,
610                                   lex_filename, dat_filename);
611     }
612     Da_ndicfile = num;
613 }