ruby-sfst 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,807 @@
1
+
2
+ /*******************************************************************/
3
+ /* */
4
+ /* FILE alphabet.C */
5
+ /* MODULE alphabet */
6
+ /* PROGRAM SFST */
7
+ /* AUTHOR Helmut Schmid, IMS, University of Stuttgart */
8
+ /* */
9
+ /* PURPOSE basic FST functions */
10
+ /* */
11
+ /*******************************************************************/
12
+
13
+ #include "utf8.h"
14
+ #include "alphabet.h"
15
+
16
+ using std::vector;
17
+ using std::ostream;
18
+ using __gnu_cxx::hash_map;
19
+ using __gnu_cxx::hash_set;
20
+
21
+ const int BUFFER_SIZE=100000;
22
+
23
+ char EpsilonString[]="<>";
24
+
25
+
26
+ /*******************************************************************/
27
+ /* */
28
+ /* Alphabet::add */
29
+ /* */
30
+ /*******************************************************************/
31
+
32
+ void Alphabet::add( const char *symbol, Character c )
33
+
34
+ {
35
+ char *s = fst_strdup(symbol);
36
+ cm[c] = s;
37
+ sm[s] = c;
38
+ }
39
+
40
+
41
+ /*******************************************************************/
42
+ /* */
43
+ /* Alphabet::Alphabet */
44
+ /* */
45
+ /*******************************************************************/
46
+
47
+ Alphabet::Alphabet()
48
+
49
+ {
50
+ utf8 = false;
51
+ add(EpsilonString, Label::epsilon);
52
+ }
53
+
54
+
55
+ /*******************************************************************/
56
+ /* */
57
+ /* Alphabet::clear */
58
+ /* */
59
+ /*******************************************************************/
60
+
61
+ void Alphabet::clear()
62
+
63
+ {
64
+ char **s=new char*[cm.size()];
65
+ ls.clear();
66
+ sm.clear();
67
+
68
+ size_t i, n=0;
69
+ for( CharMap::iterator it=cm.begin(); it!=cm.end(); it++ )
70
+ s[n++] = it->second;
71
+ cm.clear();
72
+
73
+ for( i=0; i<n; i++ )
74
+ free(s[i]);
75
+ delete[] s;
76
+ }
77
+
78
+
79
+ /*******************************************************************/
80
+ /* */
81
+ /* Alphabet::new_marker */
82
+ /* */
83
+ /*******************************************************************/
84
+
85
+ Character Alphabet::new_marker()
86
+
87
+ {
88
+ // find some unused character code
89
+ for(Character i=1; i!=0; i++)
90
+ if (cm.find(i) == cm.end()) {
91
+ // create a unique identifier string
92
+ char symbol[100];
93
+ sprintf(symbol,">%ld<",(long)i);
94
+ add(symbol, i);
95
+ return i;
96
+ }
97
+
98
+ throw "Error: too many symbols in transducer definition";
99
+ }
100
+
101
+
102
+ /*******************************************************************/
103
+ /* */
104
+ /* is_marker_symbol */
105
+ /* */
106
+ /*******************************************************************/
107
+
108
+ static bool is_marker_symbol( const char *s )
109
+
110
+ {
111
+ // recogize strings matching the expression ">[0-9]+<"
112
+ if (s != NULL && *s == '>') {
113
+ do { s++; } while (*s >= '0' && *s <= '9');
114
+ if (*s=='<' && *(s+1) == 0 && *(s-1) != '>')
115
+ return true;
116
+ }
117
+ return false;
118
+ }
119
+
120
+
121
+ /*******************************************************************/
122
+ /* */
123
+ /* Alphabet::delete_markers */
124
+ /* */
125
+ /*******************************************************************/
126
+
127
+ void Alphabet::delete_markers()
128
+
129
+ {
130
+ vector<char*> sym;
131
+ vector<Character> code;
132
+ vector<Label> label;
133
+
134
+ for( CharMap::const_iterator it=cm.begin(); it!=cm.end(); it++ ) {
135
+ Character c=it->first;
136
+ char *s=it->second;
137
+ if (!is_marker_symbol(s)) {
138
+ sym.push_back(fst_strdup(s));
139
+ code.push_back(c);
140
+ }
141
+ }
142
+
143
+ for( LabelSet::const_iterator it=begin(); it!=end(); it++ ) {
144
+ Label l=*it;
145
+ if (!is_marker_symbol(code2symbol(l.upper_char())) &&
146
+ !is_marker_symbol(code2symbol(l.lower_char())))
147
+ label.push_back(l);
148
+ }
149
+
150
+ clear();
151
+
152
+ for( size_t i=0; i<sym.size(); i++ ) {
153
+ add_symbol(sym[i], code[i]);
154
+ free(sym[i]);
155
+ }
156
+ for( size_t i=0; i<label.size(); i++ )
157
+ insert( label[i] );
158
+ }
159
+
160
+
161
+ /*******************************************************************/
162
+ /* */
163
+ /* Alphabet::add_symbol */
164
+ /* */
165
+ /*******************************************************************/
166
+
167
+ Character Alphabet::add_symbol(const char *symbol)
168
+
169
+ {
170
+ if (sm.find(symbol) != sm.end())
171
+ return sm[symbol];
172
+
173
+ // assign the symbol to some unused character
174
+ for(Character i=1; i!=0; i++)
175
+ if (cm.find(i) == cm.end()) {
176
+ add(symbol, i);
177
+ return i;
178
+ }
179
+
180
+ throw "Error: too many symbols in transducer definition";
181
+ }
182
+
183
+
184
+ /*******************************************************************/
185
+ /* */
186
+ /* Alphabet::add_symbol */
187
+ /* */
188
+ /*******************************************************************/
189
+
190
+ void Alphabet::add_symbol( const char *symbol, Character c )
191
+
192
+ {
193
+ // check whether the symbol was previously defined
194
+ int sc=symbol2code(symbol);
195
+ if (sc != EOF) {
196
+ if ((Character)sc == c)
197
+ return;
198
+
199
+ if (strlen(symbol) < 60) {
200
+ static char message[100];
201
+ sprintf(message, "Error: reinserting symbol '%s' in alphabet with incompatible character value %u %u", symbol, (unsigned)sc, (unsigned)c);
202
+ throw message;
203
+ }
204
+ else
205
+ throw "reinserting symbol in alphabet with incompatible character value";
206
+ }
207
+
208
+ // check whether the character is already in use
209
+ const char *s=code2symbol(c);
210
+ if (s == NULL)
211
+ add(symbol, c);
212
+ else {
213
+ if (strcmp(s, symbol) != 0) {
214
+ static char message[100];
215
+ if (strlen(symbol) < 70)
216
+ sprintf(message,"Error: defining symbol %s as character %d (previously defined as %s)", symbol, (unsigned)c, s);
217
+ else
218
+ sprintf(message,"Error: defining a (very long) symbol with previously used character");
219
+ throw message;
220
+ }
221
+ }
222
+ }
223
+
224
+
225
+ /*******************************************************************/
226
+ /* */
227
+ /* Alphabet::write_char */
228
+ /* */
229
+ /*******************************************************************/
230
+
231
+ void Alphabet::write_char( Character c, char *buffer, int *pos,
232
+ bool with_brackets) const
233
+ {
234
+ const char *s = code2symbol(c);
235
+
236
+ if (s) {
237
+ int i = 0;
238
+ int l=strlen(s)-1;
239
+ if (!with_brackets && s[i] == '<' && s[l] == '>') { i++; l--; }
240
+ while (i <= l)
241
+ buffer[(*pos)++] = s[i++];
242
+ }
243
+ else {
244
+ unsigned int uc = c;
245
+ if (uc>=32 && uc<256)
246
+ buffer[(*pos)++] = (char)c;
247
+ else {
248
+ sprintf(buffer+(*pos),"\\%u", uc);
249
+ *pos += strlen(buffer+(*pos));
250
+ }
251
+ }
252
+ buffer[*pos] = '\0';
253
+ }
254
+
255
+
256
+ /*******************************************************************/
257
+ /* */
258
+ /* Alphabet::write_char */
259
+ /* */
260
+ /*******************************************************************/
261
+
262
+ const char *Alphabet::write_char( Character c, bool with_brackets ) const
263
+
264
+ {
265
+ static char buffer[1000];
266
+ int n=0;
267
+
268
+ write_char( c, buffer, &n, with_brackets );
269
+ return buffer;
270
+ }
271
+
272
+
273
+ /*******************************************************************/
274
+ /* */
275
+ /* Alphabet::write_label */
276
+ /* */
277
+ /*******************************************************************/
278
+
279
+ void Alphabet::write_label( Label l, char *buffer, int *pos,
280
+ bool with_brackets ) const
281
+ {
282
+ Character lc=l.lower_char();
283
+ Character uc=l.upper_char();
284
+ write_char( lc, buffer, pos, with_brackets );
285
+ if (lc != uc) {
286
+ buffer[(*pos)++] = ':';
287
+ write_char( uc, buffer, pos, with_brackets );
288
+ }
289
+ }
290
+
291
+
292
+ /*******************************************************************/
293
+ /* */
294
+ /* Alphabet::write_label */
295
+ /* */
296
+ /*******************************************************************/
297
+
298
+ const char *Alphabet::write_label( Label l, bool with_brackets ) const
299
+
300
+ {
301
+ static char buffer[1000];
302
+ int n=0;
303
+ write_label( l, buffer, &n, with_brackets );
304
+ return buffer;
305
+ }
306
+
307
+
308
+ /*******************************************************************/
309
+ /* */
310
+ /* Alphabet::insert_symbols */
311
+ /* */
312
+ /*******************************************************************/
313
+
314
+ void Alphabet::insert_symbols( const Alphabet &a )
315
+
316
+ {
317
+ for( CharMap::const_iterator it=a.cm.begin(); it!=a.cm.end(); it++ )
318
+ add_symbol(it->second, it->first);
319
+ }
320
+
321
+
322
+ /*******************************************************************/
323
+ /* */
324
+ /* Alphabet::complement */
325
+ /* */
326
+ /*******************************************************************/
327
+
328
+ void Alphabet::complement( vector<Character> &sym )
329
+
330
+ {
331
+ vector<Character> result;
332
+ for( CharMap::const_iterator it=cm.begin(); it!=cm.end(); it++ ) {
333
+ Character c = it->first;
334
+ if (c != Label::epsilon) {
335
+ size_t i;
336
+ for( i=0; i<sym.size(); i++ )
337
+ if (sym[i] == c)
338
+ break;
339
+ if (i == sym.size())
340
+ result.push_back(c);
341
+ }
342
+ }
343
+ sym.swap(result);
344
+ }
345
+
346
+
347
+ /*******************************************************************/
348
+ /* */
349
+ /* Alphabet::copy */
350
+ /* */
351
+ /*******************************************************************/
352
+
353
+ void Alphabet::copy( const Alphabet &a )
354
+
355
+ {
356
+ insert_symbols( a );
357
+ utf8 = a.utf8;
358
+ for( LabelSet::const_iterator it=a.begin(); it!=a.end(); it++ )
359
+ ls.insert( *it );
360
+ }
361
+
362
+
363
+ /*******************************************************************/
364
+ /* */
365
+ /* Alphabet::compose */
366
+ /* */
367
+ /*******************************************************************/
368
+
369
+ void Alphabet::compose( const Alphabet &la, const Alphabet &ua )
370
+
371
+ {
372
+ // insert the symbols
373
+ insert_symbols(la);
374
+ insert_symbols(ua);
375
+ utf8 = la.utf8;
376
+
377
+ hash_map<Character, hash_set<Character> > cs;
378
+
379
+ // create a hash table for a quick lookup of the target characters
380
+ for( iterator it=ua.begin(); it!=ua.end(); it++ ) {
381
+ Character lc=it->lower_char();
382
+ if (lc == Label::epsilon)
383
+ insert(*it);
384
+ else
385
+ cs[lc].insert(it->upper_char());
386
+ }
387
+
388
+ for( iterator it=la.begin(); it!=la.end(); it++ ) {
389
+ Character uc=it->upper_char();
390
+ if (uc == Label::epsilon)
391
+ insert(*it);
392
+ else {
393
+ if (cs.find(uc) != cs.end()) {
394
+ hash_set<Character> s=cs[uc];
395
+ Character lc=it->lower_char();
396
+ for( hash_set<Character>::iterator it=s.begin(); it!=s.end(); it++)
397
+ insert(Label(lc, *it));
398
+ }
399
+ }
400
+ }
401
+ }
402
+
403
+
404
+ /*******************************************************************/
405
+ /* */
406
+ /* operator<<(Alphabet) */
407
+ /* */
408
+ /*******************************************************************/
409
+
410
+ ostream &operator<<( ostream &s, const Alphabet &a )
411
+
412
+ {
413
+ for( Alphabet::CharMap::const_iterator it=a.cm.begin(); it!=a.cm.end(); it++ )
414
+ s << it->first << " -> " << it->second << "\n";
415
+ for( Alphabet::iterator it=a.begin(); it!=a.end(); it++ )
416
+ s << a.write_label(*it) << " ";
417
+ s << "\n";
418
+ return s;
419
+ }
420
+
421
+
422
+ /*******************************************************************/
423
+ /* */
424
+ /* Alphabet::next_mcsym */
425
+ /* */
426
+ /* recognizes multi-character symbols which are enclosed with */
427
+ /* angle brackets <...>. If the value of the argument flag is */
428
+ /* smaller than 2, the multi-character symbol must be already in */
429
+ /* the lexicon in order to be recognized. */
430
+ /* */
431
+ /*******************************************************************/
432
+
433
+ int Alphabet::next_mcsym( char* &string, int extended )
434
+
435
+ {
436
+ char *start=string;
437
+
438
+ if (*start == '<')
439
+ // symbol might start here
440
+ for( char *end=start+1; *end; end++ )
441
+ if (*end == '>') {
442
+ // matching pair of angle brackets found
443
+ // mark the end of the substring with \0
444
+ char lastc = *(++end);
445
+ *end = 0;
446
+
447
+ int c;
448
+ if (extended <= 2)
449
+ c = add_symbol( start );
450
+ else
451
+ c = symbol2code(start);
452
+ // restore the original string
453
+ *end = lastc;
454
+
455
+ if (c != EOF) {
456
+ // symbol found
457
+ // return its code
458
+ string = end;
459
+ return (Character)c;
460
+ }
461
+ else
462
+ // not a complex character
463
+ break;
464
+ }
465
+ return EOF;
466
+ }
467
+
468
+
469
+ /*******************************************************************/
470
+ /* */
471
+ /* Alphabet::next_code */
472
+ /* */
473
+ /*******************************************************************/
474
+
475
+ int Alphabet::next_code( char* &string, int extended )
476
+
477
+ {
478
+ if (*string == 0)
479
+ return EOF; // finished
480
+
481
+ int c = next_mcsym(string, extended);
482
+ if (c != EOF)
483
+ return c;
484
+
485
+ if (extended && *string == '\\')
486
+ string++; // remove quotation
487
+
488
+ if (utf8) {
489
+ unsigned int c = utf8toint( &string );
490
+ return (int)add_symbol(int2utf8(c));
491
+ }
492
+ else {
493
+ char buffer[2];
494
+ buffer[0] = *string;
495
+ buffer[1] = 0;
496
+ string++;
497
+ return (int)add_symbol(buffer);
498
+ }
499
+ }
500
+
501
+
502
+ /*******************************************************************/
503
+ /* */
504
+ /* Alphabet::next_label */
505
+ /* */
506
+ /*******************************************************************/
507
+
508
+ Label Alphabet::next_label( char* &string, int extended )
509
+
510
+ {
511
+ // read first character
512
+ int c = next_code( string, extended );
513
+ if (c == EOF)
514
+ return Label(); // end of string reached
515
+
516
+ Character lc=(Character)c;
517
+ if (!extended || *string != ':') { // single character?
518
+ if (lc == Label::epsilon)
519
+ return next_label(string); // ignore epsilon
520
+ return Label(lc);
521
+ }
522
+
523
+ // read second character
524
+ string++; // jump over ':'
525
+ c = next_code( string );
526
+ if (c == EOF) {
527
+ static char buffer[1000];
528
+ sprintf(buffer,"Error: incomplete symbol in input file: %s", string);
529
+ throw buffer;
530
+ }
531
+
532
+ Label l(lc, (Character)c);
533
+ if (l.is_epsilon())
534
+ return next_label(string); // ignore epsilon transitions
535
+ return l;
536
+ }
537
+
538
+
539
+ /*******************************************************************/
540
+ /* */
541
+ /* Alphabet::string2symseq */
542
+ /* */
543
+ /*******************************************************************/
544
+
545
+ void Alphabet::string2symseq( char *s, vector<Character> &ch )
546
+
547
+ {
548
+ int c;
549
+ while ((c = next_code(s, false)) != EOF)
550
+ ch.push_back((Character)c);
551
+ }
552
+
553
+
554
+ /*******************************************************************/
555
+ /* */
556
+ /* Alphabet::string2labelseq */
557
+ /* */
558
+ /*******************************************************************/
559
+
560
+ void Alphabet::string2labelseq( char *s, vector<Label> &labels )
561
+
562
+ {
563
+ Label l;
564
+ while ((l = next_label(s)) != Label::epsilon)
565
+ labels.push_back(l);
566
+ }
567
+
568
+
569
+ /*******************************************************************/
570
+ /* */
571
+ /* Alphabet::store */
572
+ /* */
573
+ /*******************************************************************/
574
+
575
+ void Alphabet::store( FILE *file ) const
576
+
577
+ {
578
+ char c=(utf8)? 1: 0;
579
+ fputc(c, file);
580
+
581
+ // write the symbol mapping
582
+ Character n=cm.size();
583
+ fwrite(&n, sizeof(n), 1, file);
584
+ for( CharMap::const_iterator it=cm.begin(); it!=cm.end(); it++ ) {
585
+ Character c=it->first;
586
+ char *s=it->second;
587
+ fwrite(&c, sizeof(c), 1, file);
588
+ fwrite(s, sizeof(char), strlen(s)+1, file);
589
+ }
590
+
591
+ // write the character pairs
592
+ n = size();
593
+ fwrite(&n, sizeof(n), 1, file);
594
+ for( LabelSet::const_iterator p=ls.begin(); p!=ls.end(); p++ ) {
595
+ Character c=p->lower_char();
596
+ fwrite(&c, sizeof(c), 1, file);
597
+ c = p->upper_char();
598
+ fwrite(&c, sizeof(c), 1, file);
599
+ }
600
+
601
+ if (ferror(file))
602
+ throw "Error encountered while writing alphabet to file\n";
603
+ }
604
+
605
+
606
+ /*******************************************************************/
607
+ /* */
608
+ /* Alphabet::read */
609
+ /* */
610
+ /*******************************************************************/
611
+
612
+ void Alphabet::read( FILE *file )
613
+
614
+ {
615
+ utf8 = (fgetc(file) != 0);
616
+
617
+ // read the symbol mapping
618
+ Character n=0;
619
+ read_num(&n, sizeof(n), file);
620
+ for( unsigned i=0; i<n; i++) {
621
+ char buffer[BUFFER_SIZE];
622
+ Character c;
623
+ read_num(&c, sizeof(c), file);
624
+ if (!read_string(buffer, BUFFER_SIZE, file) ||
625
+ feof(file) || ferror(file))
626
+ throw "Error1 occurred while reading alphabet!\n";
627
+ add_symbol(buffer, c);
628
+ }
629
+
630
+ // read the character pairs
631
+ read_num(&n, sizeof(n), file);
632
+ if (ferror(file))
633
+ throw "Error2 occurred while reading alphabet!\n";
634
+ for( unsigned i=0; i<n; i++) {
635
+ Character lc, uc;
636
+ read_num(&lc, sizeof(lc), file);
637
+ read_num(&uc, sizeof(uc), file);
638
+ insert(Label(lc, uc));
639
+ }
640
+ if (ferror(file))
641
+ throw "Error3 occurred while reading alphabet!\n";
642
+ }
643
+
644
+
645
+ /*******************************************************************/
646
+ /* */
647
+ /* Alphabet::compute_score */
648
+ /* */
649
+ /*******************************************************************/
650
+
651
+ int Alphabet::compute_score( Analysis &ana )
652
+
653
+ {
654
+ // check whether the morpheme boundaries are explicitly marked
655
+ // with <X> tags
656
+ int score=0;
657
+ for( size_t i=0; i<ana.size(); i++ ) {
658
+
659
+ // get next symbol
660
+ const char *sym=write_char(ana[i].lower_char());
661
+
662
+ if (strcmp(sym,"<X>") == 0)
663
+ score--;
664
+ }
665
+ if (score < 0)
666
+ return score;
667
+
668
+ // No explicit morphome boundary markers have been found.
669
+ // Count the number of part-of-speech and PREF tags.
670
+ for( size_t i=0; i<ana.size(); i++ ) {
671
+
672
+ // get next symbol
673
+ const char *sym=write_char(ana[i].lower_char());
674
+
675
+ // Is it not a multi-character symbol
676
+ if (sym[0] != '<' || sym[1] == 0)
677
+ continue;
678
+
679
+ // Is it a POS tag starting with "+" like <+NN>?
680
+ if (sym[1] == '+') {
681
+ const char *t=sym+2;
682
+ for( ; *t >= 'A' && *t <= 'Z'; t++) ;
683
+ if (t > sym+2 && *t == '>')
684
+ return score;
685
+ }
686
+
687
+ // Is it a potential POS tag (i.e. all uppercase)?
688
+ const char *t = sym+1;
689
+ for( ; *t >= 'A' && *t <= 'Z'; t++) ;
690
+ if (t == sym+1 || *t != '>')
691
+ continue;
692
+
693
+ // uppercase symbol found
694
+ if (strcmp(sym,"<SUFF>") == 0 ||
695
+ strcmp(sym,"<OLDORTH>") == 0 ||
696
+ strcmp(sym,"<NEWORTH>") == 0)
697
+ continue; // not what we are looking for
698
+
699
+ // disprefer nouns with prefixes
700
+ if (strcmp(sym,"<PREF>") == 0)
701
+ score-=2;
702
+
703
+ if (strcmp(sym,"<V>") == 0 || strcmp(sym,"<ADJ>") == 0) {
704
+ bool is_verb=(strcmp(sym,"<V>")==0);
705
+ // get the next non-empty symbol
706
+ Character c=Label::epsilon;
707
+ size_t k;
708
+ for( k=i+1; k<ana.size(); k++ )
709
+ if ((c = ana[k].lower_char()) != Label::epsilon)
710
+ break;
711
+ // Is it a participle
712
+ if (c != Label::epsilon) {
713
+ sym = write_char(c);
714
+ if (strcmp(sym,"<OLDORTH>") == 0 || strcmp(sym,"<NEWORTH>") == 0) {
715
+ for( k++; k<ana.size(); k++ )
716
+ if ((c = ana[k].lower_char()) != Label::epsilon)
717
+ break;
718
+ if (c != Label::epsilon)
719
+ sym = write_char(c);
720
+ }
721
+ if (is_verb &&
722
+ (strcmp(sym,"<PPres>") == 0 || strcmp(sym,"<PPast>") == 0))
723
+ continue; // don't consider participles as complex
724
+ if (!is_verb &&
725
+ (strcmp(sym,"<Sup>") == 0 || strcmp(sym,"<Comp>") == 0))
726
+ continue; // don't consider participles as complex
727
+ }
728
+ }
729
+ score--;
730
+ }
731
+ return score;
732
+ }
733
+
734
+
735
+
736
+ /*******************************************************************/
737
+ /* */
738
+ /* Alphabet::disambiguate */
739
+ /* */
740
+ /*******************************************************************/
741
+
742
+ void Alphabet::disambiguate( vector<Analysis> &analyses )
743
+
744
+ {
745
+ // compute the scores
746
+ int bestscore=INT_MIN;
747
+ vector<int> score;
748
+
749
+ for( size_t i=0; i<analyses.size(); i++ ) {
750
+ score.push_back(compute_score(analyses[i]));
751
+ if (bestscore < score[i])
752
+ bestscore = score[i];
753
+ }
754
+
755
+ // delete suboptimal analyses
756
+ size_t k=0;
757
+ for( size_t i=0; i<analyses.size(); i++ )
758
+ if (score[i] == bestscore)
759
+ analyses[k++] = analyses[i];
760
+ analyses.resize(k);
761
+ }
762
+
763
+
764
+
765
+ /*******************************************************************/
766
+ /* */
767
+ /* Alphabet::print_analysis */
768
+ /* */
769
+ /*******************************************************************/
770
+
771
+ char *Alphabet::print_analysis( Analysis &ana, bool both_layers )
772
+
773
+ {
774
+ vector<char> ch;
775
+
776
+ // for each transition
777
+ for( size_t i=0; i<ana.size(); i++ ) {
778
+
779
+ // get the transition label
780
+ Label l=ana[i];
781
+ const char *s;
782
+
783
+ // either print the analysis symbol or the whole label
784
+ if (both_layers)
785
+ s = write_label(l);
786
+ else if (l.lower_char() != Label::epsilon)
787
+ s = write_char(l.lower_char());
788
+ else
789
+ continue;
790
+
791
+ // copy the characters to the character array
792
+ while (*s)
793
+ ch.push_back(*(s++));
794
+ }
795
+ ch.push_back(0); // terminate the string
796
+
797
+ static char *result=NULL;
798
+ if (result != NULL)
799
+ delete[] result;
800
+ result = new char[ch.size()];
801
+ for( size_t i=0; i<ch.size(); i++ )
802
+ result[i] = ch[i];
803
+
804
+ return result;
805
+ }
806
+
807
+