ruby-sfst 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+