Bug Summary

File:modules/base/phrasify.cc
Location:line 617, column 5
Description:Value stored to 'lang_prob' is never read

Annotated Source Code

1/*************************************************************************/
2/* */
3/* Centre for Speech Technology Research */
4/* University of Edinburgh, UK */
5/* Copyright (c) 1996,1997 */
6/* All Rights Reserved. */
7/* */
8/* Permission is hereby granted, free of charge, to use and distribute */
9/* this software and its documentation without restriction, including */
10/* without limitation the rights to use, copy, modify, merge, publish, */
11/* distribute, sublicense, and/or sell copies of this work, and to */
12/* permit persons to whom this work is furnished to do so, subject to */
13/* the following conditions: */
14/* 1. The code must retain the above copyright notice, this list of */
15/* conditions and the following disclaimer. */
16/* 2. Any modifications must be clearly marked as such. */
17/* 3. Original authors' names are not deleted. */
18/* 4. The authors' names are not used to endorse or promote products */
19/* derived from this software without specific prior written */
20/* permission. */
21/* */
22/* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23/* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24/* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25/* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26/* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28/* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30/* THIS SOFTWARE. */
31/* */
32/*************************************************************************/
33/* Author : Alan W Black */
34/* Date : August 1996 */
35/*-----------------------------------------------------------------------*/
36/* */
37/* Phrase break prediction */
38/* */
39/*=======================================================================*/
40#include <cstdio>
41#include "festival.h"
42#include "modules.h"
43
44using namespace std;
45
46static void phrasing_none(EST_Utterance &u);
47static void phrasing_by_cart(EST_Utterance &u);
48static void phrasing_by_probmodels(EST_Utterance &u);
49static void phrasing_by_fa(EST_Utterance &u);
50static EST_VTCandidate *bb_candlist(EST_Item *s,EST_Features &f);
51static EST_VTPath *bb_npath(EST_VTPath *p,EST_VTCandidate *c,EST_Features &f);
52static double find_b_prob(EST_VTPath *p,int n,int *state);
53
54// Used in various default value cases
55static int B_word = 0;
56static int BB_word = 0;
57static int NB_word = 0;
58static int pos_p_start_tag = 0;
59static int pos_pp_start_tag = 0;
60static int pos_n_start_tag = 0;
61
62static double gscale_s = 1.0;
63static double gscale_p = 0.0;
64static EST_Ngrammar *bb_ngram = 0;
65static EST_Ngrammar *bb_pos_ngram = 0;
66static LISP bb_tags = NIL((struct obj *) 0);
67static LISP pos_map = NIL((struct obj *) 0);
68static LISP phrase_type_tree = NIL((struct obj *) 0);
69
70/* Interslice */
71static EST_Track *bb_track = 0;
72
73LISP FT_Classic_Phrasify_Utt(LISP utt)
74{
75 // Predict and add phrasing to an utterance
76 EST_Utterance *u = get_c_utt(utt)(utterance(utt));
77 LISP phrase_method = ft_get_param("Phrase_Method");
78
79 *cdebug << "Phrasify module\n";
80
81 if (u->relation_present("Phrase"))
82 return utt; // already specified
83 else if (phrase_method == NIL((struct obj *) 0))
84 phrasing_none(*u); // all one phrase
85 else if (streq("prob_models",get_c_string(phrase_method))(strcmp("prob_models",get_c_string(phrase_method))==0))
86 phrasing_by_probmodels(*u);
87 else if (streq("cart_tree",get_c_string(phrase_method))(strcmp("cart_tree",get_c_string(phrase_method))==0))
88 phrasing_by_cart(*u);
89 else if (streq("forced_align",get_c_string(phrase_method))(strcmp("forced_align",get_c_string(phrase_method))==0))
90 phrasing_by_fa(*u);
91 else
92 {
93 cerr << "PHRASIFY: unknown phrase method \"" <<
94 get_c_string(phrase_method) << endl;
95 festival_error()(errjmp_ok ? longjmp(*est_errjmp,1) : festival_tidy_up(),exit
(-1))
;
96 }
97
98 return utt;
99}
100
101static void phrasing_none(EST_Utterance& u)
102{
103 // All in a single phrase
104 EST_Item *w,*phr=0;
105
106 u.create_relation("Phrase");
107
108 for (w=u.relation("Word")->first(); w != 0; w = w->next())
109 {
110 if (phr == 0)
111 phr = add_phrase(u);
112 append_daughter(phr,"Phrase",w);
113 if (w->next() == 0)
114 {
115 w->set("pbreak","B");
116 phr->set_name("4");
117 phr = 0;
118 }
119 }
120
121}
122
123static void phrasing_by_cart(EST_Utterance &u)
124{
125 EST_Item *w,*phr=0;
126 LISP tree;
127 EST_Val pbreak;
128
129 u.create_relation("Phrase");
130 tree = siod_get_lval("phrase_cart_tree","no phrase cart tree");
131
132 for (w=u.relation("Word")->first(); w != 0; w = w->next())
133 {
134 if (phr == 0)
135 phr = add_phrase(u);
136 append_daughter(phr,"Phrase",w);
137 pbreak = wagon_predict(w,tree);
138 w->set("pbreak",pbreak.string());
139 if ((pbreak == "B") || (pbreak == "BB"))
140 {
141 phr->set_name((EST_String)pbreak);
142 phr = 0;
143 }
144 }
145
146}
147
148static void pbyp_get_params(LISP params)
149{
150 EST_String bb_pos_name,bb_pos_filename,bb_name,bb_break_filename;
151 EST_String bb_track_name;
152 LISP l1;
153
154 bb_pos_name = get_param_str("pos_ngram_name",params,"");
155 bb_pos_filename = get_param_str("pos_ngram_filename",params,"");
156 if ((bb_pos_ngram = get_ngram(bb_pos_name,bb_pos_filename)) == 0)
157 {
158 cerr << "PHRASIFY: no ngram called \"" <<
159 bb_pos_name << "\" defined." << endl;
160 festival_error()(errjmp_ok ? longjmp(*est_errjmp,1) : festival_tidy_up(),exit
(-1))
;
161 }
162
163 gscale_s = get_param_float("gram_scale_s",params,1.0);
164 gscale_p = get_param_float("gram_scale_p",params,0.0);
165 pos_map = get_param_lisp("pos_map",params,NIL((struct obj *) 0));
166
167 bb_name = get_param_str("break_ngram_name",params,"");
168 bb_break_filename = get_param_str("break_ngram_filename",params,"");
169 if ((bb_ngram = get_ngram(bb_name,bb_break_filename)) == 0)
170 {
171 cerr << "PHRASIFY: no ngram called \"" <<
172 bb_name << "\" defined." << endl;
173 festival_error()(errjmp_ok ? longjmp(*est_errjmp,1) : festival_tidy_up(),exit
(-1))
;
174 }
175 bb_tags = get_param_lisp("break_tags",params,NIL((struct obj *) 0));
176 phrase_type_tree = get_param_lisp("phrase_type_tree",params,NIL((struct obj *) 0));
177
178 bb_track_name = get_param_str("break_track_name",params,"");
179 if (bb_track_name != "")
180 {
181 if (bb_track)
182 delete bb_track;
183 bb_track = new EST_Track;
184 if (bb_track->load(bb_track_name) != format_okread_ok)
185 {
186 delete bb_track;
187 cerr << "PHRASE: failed to load FA track " <<
188 bb_track_name << endl;
189 festival_error()(errjmp_ok ? longjmp(*est_errjmp,1) : festival_tidy_up(),exit
(-1))
;
190 }
191 }
192
193 l1 = siod_get_lval("pos_p_start_tag",NULL__null);
194 if (l1 != NIL((struct obj *) 0))
195 pos_p_start_tag = bb_pos_ngram->get_vocab_word(get_c_string(l1));
196 l1 = siod_get_lval("pos_pp_start_tag",NULL__null);
197 if (l1 != NIL((struct obj *) 0))
198 pos_pp_start_tag = bb_pos_ngram->get_vocab_word(get_c_string(l1));
199 l1 = siod_get_lval("pos_n_start_tag",NULL__null);
200 if (l1 != NIL((struct obj *) 0))
201 pos_n_start_tag = bb_pos_ngram->get_vocab_word(get_c_string(l1));
202}
203
204static void phrasing_by_probmodels(EST_Utterance& u)
205{
206 // Predict phrasing using POS and prob models of B distribution
207 EST_Item *w,*phr=0;
208 EST_String pbreak;
209 int num_states;
210
211 pbyp_get_params(siod_get_lval("phr_break_params",NULL__null));
212 gc_protect(&bb_tags);
213
214 for (w=u.relation("Word")->first(); w != 0; w = w->next())
215 { // Set up tag index for pos ngram
216 EST_String lpos = map_pos(pos_map,w->f("pos").string());
217 w->set("phr_pos",lpos);
218 w->set("pos_index",bb_pos_ngram->get_vocab_word(lpos));
219 }
220 B_word = bb_ngram->get_vocab_word("B");
221 NB_word = bb_ngram->get_vocab_word("NB");
222 BB_word = bb_ngram->get_vocab_word("BB");
223
224 num_states = bb_ngram->num_states();
225 EST_Viterbi_Decoder v(bb_candlist,bb_npath,num_states);
226
227 v.initialise(u.relation("Word"));
228 v.search();
229 v.result("pbreak_index");
230
231 // Given predicted break, go through and add phrases
232 u.create_relation("Phrase");
233 for (w=u.relation("Word")->first(); w != 0; w = w->next())
234 {
235 w->set("pbreak",bb_ngram->
236 get_vocab_word(w->f("pbreak_index").Int()));
237 if (phr == 0)
238 phr = add_phrase(u);
239 append_daughter(phr,"Phrase",w);
240 if (phrase_type_tree != NIL((struct obj *) 0))
241 {
242 EST_Val npbreak = wagon_predict(w,phrase_type_tree);
243 w->set("pbreak",npbreak.string()); // may reset to BB
244 }
245 pbreak = (EST_String)w->f("pbreak");
246 if (pbreak == "B")
247 w->set("blevel",3);
248 else if (pbreak == "mB")
249 w->set("blevel",2);
250 if ((pbreak == "B") || (pbreak == "BB") || (pbreak == "mB"))
251 {
252 phr->set_name((EST_String)pbreak);
253 phr = 0;
254 }
255 }
256
257 gc_unprotect(&bb_tags);
258 bb_tags = NIL((struct obj *) 0);
259}
260
261static EST_VTCandidate *bb_candlist(EST_Item *s,EST_Features &f)
262{
263 // Find candidates with a priori probabilities
264 EST_IVector window(bb_pos_ngram->order());
265 (void)f;
266 int tag;
267
268 if (bb_pos_ngram->order() == 4)
269 {
270 window[1] = s->I("pos_index",0);
271 if (s->prev() != 0)
272 window[0] = s->prev()->I("pos_index",0);
273 else
274 window[0] = pos_p_start_tag;
275 if (s->next() != 0)
276 window[2] = s->next()->I("pos_index",0);
277 else
278 window[2] = pos_n_start_tag;
279 }
280 else if (bb_pos_ngram->order() == 3)
281 {
282 window[0] = s->I("pos_index",0);
283 if (s->next() != 0)
284 window[1] = s->next()->I("pos_index",0);
285 else
286 window[1] = pos_n_start_tag;
287 }
288 else if (bb_pos_ngram->order() == 5)
289 { // This is specific for some set of pos tagsets
290 window[2] = s->I("pos_index",0);
291 if (s->prev() != 0)
292 {
293 window[1] = s->prev()->I("pos_index",0);
294 }
295 else
296 {
297 window[1] = pos_p_start_tag;
298 }
299 if (s->next() != 0)
300 {
301 window[3] = s->next()->I("pos_index",0);
302 if (s->next()->next() != 0)
303 window[0] = s->next()->next()->I("pos_index",0);
304 else
305 window[0] = 0;
306 }
307 else
308 {
309 window[3] = pos_n_start_tag;
310 window[0] = 0;
311 }
312 }
313 else
314 {
315 cerr << "PHRASIFY: can't deal with ngram of size " <<
316 bb_pos_ngram->order() << endl;
317 festival_error()(errjmp_ok ? longjmp(*est_errjmp,1) : festival_tidy_up(),exit
(-1))
;
318 }
319 double prob=1.0;
320 EST_VTCandidate *all_c = 0;
321 EST_Val labelled_brk = ffeature(s,"R:Token.parent.pbreak");
322
323 if ((labelled_brk != "0") &&
324 (ffeature(s,"R:Token.n.name") == "0")) // last word in token
325 { // there is a labelled break on the token so respect it
326 EST_VTCandidate *c = new EST_VTCandidate;
327 c->s = s;
328 c->name = bb_ngram->get_vocab_word(labelled_brk.string());
329 c->score = log(0.95); // very very likely, but not absolute
330 c->next = all_c;
331 all_c = c; // but then if you give only one option ...
332 }
333 else if (s->next() == 0) // end of utterances so force a break
334 {
335 EST_VTCandidate *c = new EST_VTCandidate;
336 c->s = s;
337 c->name = B_word;
338 c->score = log(0.95); // very very likely, but not absolute
339 c->next = all_c;
340 all_c = c;
341 }
342 else if (s->name() == ".end_utt")
343 { // This is a quick check to see if forcing "." to B is worth it
344 EST_VTCandidate *c = new EST_VTCandidate;
345 c->s = s;
346 c->name = B_word;
347 c->score = log(0.95); // very very likely, but not absolute
348 c->next = all_c;
349 all_c = c;
350 }
351 else if (siod_get_lval("break_non_bayes",NULL__null) != NIL((struct obj *) 0))
352 {
353 /* This uses the "wrong" formula to extract the probability */
354 /* Extract P(B | context) rather than P(context | B) as below */
355 /* This gives worse results as well as not following Bayes */
356 /* equations */
357 EST_VTCandidate *c;
358 LISP l;
359 for (l=bb_tags; l != 0; l=cdr(l))
360 {
361 c = new EST_VTCandidate;
362 c->s = s;
363 tag = bb_ngram->get_vocab_word(get_c_string(car(l)));
364 c->name = tag;
365 window[bb_pos_ngram->order()-1] = tag;
366 const EST_DiscreteProbDistribution &pd =
367 bb_pos_ngram->prob_dist(window);
368 if (pd.samples() == 0)
369 {
370 if (tag == B_word)
371 prob = 0.2;
372 else
373 prob = 0.8;
374 }
375 else
376 prob = pd.probability(tag);
377 if (prob == 0)
378 c->score = log(0.0000001);
379 else
380 c->score = log(prob);
381 c->next = all_c;
382 all_c = c;
383 }
384 }
385 else
386 { // Standard Bayes model
387 EST_VTCandidate *c;
388 LISP l;
389 for (l=bb_tags; l != 0; l=cdr(l))
390 {
391 c = new EST_VTCandidate;
392 c->s = s;
393 tag = bb_ngram->get_vocab_word(get_c_string(car(l)));
394 c->name = tag;
395 window[bb_pos_ngram->order()-1] = tag;
396 prob = bb_pos_ngram->reverse_probability(window);
397
398 // If this word came from inside a token reduce the
399 // probability of a break
400 if ((ffeature(s,"R:Token.n.name") != "0") &&
401 ((s->as_relation("Token")->first()->length()) < 7))
402 {
403 float weight = ffeature(s,"pbreak_scale");
404 if (weight == 0) weight = 0.5;
405 if (tag == B_word)
406 prob *= weight;
407 else
408 prob = 1.0-((1.0-prob)*weight);
409 }
410 if (prob == 0)
411 c->score = log(0.0000001);
412 else
413 c->score = log(prob);
414 s->set("phrase_score",c->score);
415 c->next = all_c;
416 all_c = c;
417 }
418 }
419
420 return all_c;
421}
422
423static EST_VTPath *bb_npath(EST_VTPath *p,EST_VTCandidate *c,EST_Features &f)
424{
425 EST_VTPath *np = new EST_VTPath;
426 (void)f;
427// static EST_String lscorename("lscore");
428 double prob;
429 double lprob,lang_prob;
430
431 np->c = c;
432 np->from = p;
433 int n = c->name.Int();
434 prob = find_b_prob(p,n,&np->state);
435 if (np->state == -1)
436 prob = find_b_prob(p,n,&np->state);
437 if (prob == 0)
438 lprob = log(0.00000001);
439 else
440 lprob = log(prob);
441
442 lang_prob = (1.0 * c->score) + gscale_p;
443 lang_prob = c->score;
444
445// np->set_feature(lscorename,lang_prob+lprob);
446 if (p==0)
447 np->score = (lang_prob+lprob);
448 else
449 np->score = (lang_prob+lprob) + p->score;
450
451 return np;
452}
453
454static double find_b_prob(EST_VTPath *p,int n,int *state)
455{
456 int oldstate=0;
457 double prob;
458
459 if (p == 0)
460 {
461 int order = bb_ngram->order();
462 EST_IVector window(order);
463 int i;
464 window.a_no_check(order-1) = n;
465 window.a_no_check(order-2) = B_word;
466 for (i=order-3; i>=0; i--)
467 window.a_no_check(i) = NB_word;
468 oldstate = bb_ngram->find_state_id(window);
469 }
470 else
471 oldstate = p->state;
472 const EST_DiscreteProbDistribution &pd = bb_ngram->prob_dist(oldstate);
473 if (pd.samples() == 0)
474 prob = 0;
475 else
476 prob = (double)pd.probability(n);
477 // This is too specific
478 if (n == B_word)
479 prob *= gscale_s;
480 *state = bb_ngram->find_next_state_id(oldstate,n);
481
482 return prob;
483
484}
485
486/* Part of Interslice */
487
488static double find_b_faprob(EST_VTPath *p,int n,int *state)
489{
490 int oldstate=0;
491 int i,j;
492 EST_VTPath *d;
493 double prob;
494 double atime, wtime, wstddev=0, z=0.0;
495 static int ATOTH_BREAK=2;
496 static int ATOTH_NBREAK=1;
497
498 if (p == 0)
499 {
500 oldstate = 0;
501 }
502 else
503 oldstate = p->state;
504
505/* if (streq("of",
506 ( p && p->c && p->c->s ? (const char *)ffeature(p->c->s,"name").String() : "null")))
507 printf("ding\n"); */
508
509 // Prob is the prob that time since last break could be
510 // generated by the duration model
511
512 // Skip over break if we're at one
513 for (i = oldstate; i < bb_track->num_frames(); i++)
514 {
515 if (bb_track->a(i,0) == ATOTH_NBREAK)
516 break;
517 }
518
519 // time since last break in words with std
520 for (wstddev=wtime=0.0,d=p; d ; d=d->from)
521 {
522 wtime += ffeature(d->c->s,"word_duration").Float();
523 wstddev += ffeature(d->c->s,"lisp_word_stddev").Float();
524 if (bb_track->a(d->state,0) == ATOTH_BREAK)
525 break;
526 }
527
528 // time since last break in acoustics
529 for (atime=0.01,j=i; j>0; j--)
530 {
531 if (bb_track->a(j,0) == ATOTH_BREAK)
532 break;
533 atime += bb_track->t(j) - ( i == 0 ? 0 : bb_track->t(j-1));
534 }
535
536 // Find best state for give time
537 if (wstddev == 0)
538 i++;
539 else if (n == B_word)
540 { /* cost of having a break here */
541 /* extend acoustics until next break */
542 for (; i < bb_track->num_frames(); i++)
543 {
544 if (bb_track->a(i,0) == ATOTH_BREAK)
545 break;
546 atime += bb_track->t(i) - ( i == 0 ? 0 : bb_track->t(i-1));
547 }
548 z = fabs((atime-wtime)/wstddev);
549 }
550 else
551 { /* cost of having a non-break here */
552 for ( i++,z = fabs((atime-wtime)/wstddev);
553 (i < bb_track->num_frames()) && (bb_track->a(i,0) == ATOTH_NBREAK);
554 i++)
555 {
556 atime += bb_track->t(i) - ( i == 0 ? 0 : bb_track->t(i-1));
557/* printf("better atime %f wtime %f wstddev %f z %f new z %f\n",
558 atime,wtime,wstddev,z,
559 fabs((atime-wtime)/wstddev)); */
560 if (fabs((atime-wtime)/wstddev) > (float)z)
561 break;
562 else
563 z = fabs((atime-wtime)/wstddev);
564 }
565 }
566
567
568 if (d && d->c && d->c->s && (d->c->s->next()->next()) == NULL__null)
569 { /* must be in final state */
570 printf("must be in final state\n");
571 if (i != bb_track->num_frames())
572 z = 0.000001;
573 }
574
575 if (z == 0)
576 printf("z == 0");
577
578 /* number hack */
579 prob = (2.0 - z)/2.0;
580/* prob = z; */
581 if (prob < 0.000001)
582 prob = 0.000001;
583 else if (prob > 0.999999)
584 prob = 0.999999;
585
586 // prob of atime given (wtime,wstddev)
587 printf("%d %d %f %f %f %f %s %s %f\n",oldstate,i,atime,wtime,wstddev,z,
588 ( p && p->c && p->c->s ? (const char *)ffeature(p->c->s,"name").String() : "null"),
589 ( n == B_word ? "B" : "NB"),
590 prob
591 );
592 if (i >= bb_track->num_frames())
593 i = bb_track->num_frames() - 1;
594 *state = i;
595
596 return prob;
597
598}
599
600static EST_VTPath *bb_fapath(EST_VTPath *p,EST_VTCandidate *c,EST_Features &f)
601{
602 EST_VTPath *np = new EST_VTPath;
603 (void)f;
604// static EST_String lscorename("lscore");
605 double prob;
606 double lprob,lang_prob;
607
608 np->c = c;
609 np->from = p;
610 int n = c->name.Int();
611 prob = find_b_faprob(p,n,&np->state);
612 if (prob == 0)
613 lprob = log(0.00000001);
614 else
615 lprob = log(prob);
616
617 lang_prob = (1.0 * c->score) + gscale_p;
Value stored to 'lang_prob' is never read
618 lang_prob = c->score;
619
620// np->set_feature(lscorename,lang_prob+lprob);
621 if (p==0)
622 np->score = (lang_prob+lprob);
623 else
624 np->score = (lang_prob+lprob) + p->score;
625
626 return np;
627}
628
629static void phrasing_by_fa(EST_Utterance& u)
630{
631 // Predict phrasing using POS and prob models of B distribution
632 EST_Item *w,*phr=0;
633 EST_String pbreak;
634 int num_states;
635
636 pbyp_get_params(siod_get_lval("phr_break_params",NULL__null));
637 gc_protect(&bb_tags);
638
639 for (w=u.relation("Word")->first(); w != 0; w = w->next())
640 { // Set up tag index for pos ngram
641 EST_String lpos = map_pos(pos_map,w->f("pos").string());
642 w->set("phr_pos",lpos);
643 w->set("pos_index",bb_pos_ngram->get_vocab_word(lpos));
644 }
645
646 num_states = bb_track->num_frames();
647
648 EST_Viterbi_Decoder v(bb_candlist,bb_fapath,num_states);
649
650 v.initialise(u.relation("Word"));
651 v.search();
652 v.result("pbreak_index");
653
654 // Given predicted break, go through and add phrases
655 u.create_relation("Phrase");
656 for (w=u.relation("Word")->first(); w != 0; w = w->next())
657 {
658 w->set("pbreak",bb_ngram->
659 get_vocab_word(w->f("pbreak_index").Int()));
660 if (phr == 0)
661 phr = add_phrase(u);
662 append_daughter(phr,"Phrase",w);
663 if (phrase_type_tree != NIL((struct obj *) 0))
664 {
665 EST_Val npbreak = wagon_predict(w,phrase_type_tree);
666 w->set("pbreak",npbreak.string()); // may reset to BB
667 }
668 pbreak = (EST_String)w->f("pbreak");
669 if (pbreak == "B")
670 w->set("blevel",3);
671 else if (pbreak == "mB")
672 w->set("blevel",2);
673 if ((pbreak == "B") || (pbreak == "BB") || (pbreak == "mB"))
674 {
675 phr->set_name((EST_String)pbreak);
676 phr = 0;
677 }
678 }
679
680 gc_unprotect(&bb_tags);
681 bb_tags = NIL((struct obj *) 0);
682}
683
684
685EST_Item *add_phrase(EST_Utterance& u)
686{
687 EST_Item *item = u.relation("Phrase")->append();
688
689 item->set_name("phrase");
690
691 return item;
692
693}
694