1 /*---------------------------------------------------------------------------*
2 * SR_GrammarImpl.c *
3 * *
4 * Copyright 2007, 2008 Nuance Communciations, Inc. *
5 * *
6 * Licensed under the Apache License, Version 2.0 (the 'License'); *
7 * you may not use this file except in compliance with the License. *
8 * *
9 * You may obtain a copy of the License at *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, software *
13 * distributed under the License is distributed on an 'AS IS' BASIS, *
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 * See the License for the specific language governing permissions and *
16 * limitations under the License. *
17 * *
18 *---------------------------------------------------------------------------*/
19
20 #include "ESR_Session.h"
21 #include "SR_AcousticModels.h"
22 #include "SR_AcousticModelsImpl.h"
23 #include "SR_Grammar.h"
24 #include "SR_GrammarImpl.h"
25 #include "SR_SemanticGraphImpl.h"
26 #include "SR_SemanticProcessorImpl.h"
27 #include "SR_VocabularyImpl.h"
28 #include "SR_NametagImpl.h"
29 #include "passert.h"
30 #include "plog.h"
31 #include "pmemory.h"
32
33 #define MTAG NULL
34
SR_Grammar_Create(SR_Grammar ** self)35 ESR_ReturnCode SR_Grammar_Create(SR_Grammar** self)
36 {
37 SR_GrammarImpl* impl;
38 ESR_ReturnCode rc;
39 ESR_BOOL exists;
40
41 impl = NEW(SR_GrammarImpl, MTAG);
42 if (impl == NULL)
43 {
44 PLogError(L("ESR_OUT_OF_MEMORY"));
45 return ESR_OUT_OF_MEMORY;
46 }
47
48 impl->Interface.addNametagToSlot = &SR_Grammar_AddNametagToSlot;
49 impl->Interface.addWordToSlot = &SR_Grammar_AddWordToSlot;
50 impl->Interface.checkParse = &SR_Grammar_CheckParse;
51 impl->Interface.compile = &SR_Grammar_Compile;
52 impl->Interface.destroy = &SR_Grammar_Destroy;
53 impl->Interface.getParameter = &SR_Grammar_GetParameter;
54 impl->Interface.getSize_tParameter = &SR_Grammar_GetSize_tParameter;
55 impl->Interface.resetAllSlots = &SR_Grammar_ResetAllSlots;
56 impl->Interface.save = &SR_Grammar_Save;
57 impl->Interface.setDispatchFunction = &SR_Grammar_SetDispatchFunction;
58 impl->Interface.setParameter = &SR_Grammar_SetParameter;
59 impl->Interface.setSize_tParameter = &SR_Grammar_SetSize_tParameter;
60 impl->Interface.setupRecognizer = &SR_Grammar_SetupRecognizer;
61 impl->Interface.unsetupRecognizer = &SR_Grammar_UnsetupRecognizer;
62 impl->Interface.setupVocabulary = &SR_Grammar_SetupVocabulary;
63 impl->syntax = NULL;
64 impl->recognizer = NULL;
65 impl->vocabulary = NULL;
66 impl->eventLog = NULL;
67 impl->logLevel = 0;
68 impl->isActivated = ESR_FALSE;
69
70 CHKLOG(rc, ESR_SessionTypeCreate(&impl->parameters));
71
72 /**
73 * Create the Semantic Graph and Processor to support CheckParse function
74 * (Since this function gets called by 'New', a semgraph and semproc are always
75 * created when the grammar is created)
76 */
77 rc = SR_SemanticGraphCreate(&impl->semgraph);
78 if (rc != ESR_SUCCESS)
79 {
80 PLogError(ESR_rc2str(rc));
81 goto CLEANUP;
82 }
83
84 rc = SR_SemanticProcessorCreate(&impl->semproc);
85 if (rc != ESR_SUCCESS)
86 {
87 PLogError(ESR_rc2str(rc));
88 goto CLEANUP;
89 }
90
91 CHKLOG(rc, ESR_SessionExists(&exists));
92 if (exists)
93 {
94 rc = ESR_SessionGetProperty(L("eventlog"), (void **)&impl->eventLog, TYPES_SR_EVENTLOG);
95 if (rc != ESR_NO_MATCH_ERROR && rc != ESR_SUCCESS)
96 {
97 PLogError(ESR_rc2str(rc));
98 goto CLEANUP;
99 }
100 rc = ESR_SessionGetSize_t(L("SREC.Recognizer.osi_log_level"), &impl->logLevel);
101 if (rc != ESR_NO_MATCH_ERROR && rc != ESR_SUCCESS)
102 {
103 PLogError(ESR_rc2str(rc));
104 goto CLEANUP;
105 }
106 }
107
108 *self = (SR_Grammar*) impl;
109 return ESR_SUCCESS;
110 CLEANUP:
111 FREE(impl);
112 return rc;
113 }
114
SR_GrammarCreate(SR_Grammar ** self)115 ESR_ReturnCode SR_GrammarCreate(SR_Grammar** self)
116 {
117 ESR_ReturnCode rc;
118
119 if (self == NULL)
120 {
121 PLogError(L("ESR_OUT_OF_MEMORY"));
122 return ESR_OUT_OF_MEMORY;
123 }
124 CHKLOG(rc, SR_Grammar_Create(self));
125 return ESR_SUCCESS;
126 CLEANUP:
127 return rc;
128 }
129
SR_Grammar_Compile(SR_Grammar * self)130 ESR_ReturnCode SR_Grammar_Compile(SR_Grammar* self)
131 {
132 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
133
134 if (!CA_CompileSyntax(impl->syntax))
135 return ESR_SUCCESS;
136 PLogError(L("ESR_FATAL_ERROR"));
137 return ESR_FATAL_ERROR;
138 }
139
140 /*
141 * The buffer for the pron is set very large because the real size is lost later on
142 * and all that is checked is whether a single phoneme will fit in the buffer. There
143 * is no concept of decrementing the bytes left. Because that code is one big monolithic
144 * piece of crap, it is very difficult to fix correctly. This kludge is appropriate
145 * because we don't have time to fix this correctly and there are probably dozens of
146 * similar problems in other parts of the code.
147 */
148
SR_Grammar_AddWordToSlot(SR_Grammar * self,const LCHAR * slot,const LCHAR * word,const LCHAR * pronunciation,int weight,const LCHAR * tag)149 ESR_ReturnCode SR_Grammar_AddWordToSlot(SR_Grammar* self, const LCHAR* slot, const LCHAR* word,
150 const LCHAR* pronunciation, int weight, const LCHAR* tag)
151 {
152 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
153 SR_Vocabulary* vocab;
154 LCHAR buffer[4096];
155 const LCHAR* input_pronunciation = pronunciation;
156 size_t len = 4096;
157 ESR_ReturnCode rc = ESR_SUCCESS, logrc;
158 int ca_rc = -99;
159
160 if ( slot != NULL )
161 {
162 if ( strlen ( slot ) >= MAX_STRING_LEN )
163 {
164 PLogError ( "SR_Grammar_AddWordToSlot slot : %s too long : Max %d", slot, MAX_STRING_LEN - 1 );
165 return ( ESR_INVALID_ARGUMENT );
166 }
167 }
168 if ( word != NULL )
169 {
170 if ( strlen ( word ) >= MAX_STRING_LEN )
171 {
172 PLogError ( "SR_Grammar_AddWordToSlot word : %s too long : Max %d", word, MAX_STRING_LEN - 1 );
173 return ( ESR_INVALID_ARGUMENT );
174 }
175 }
176 if ( pronunciation != NULL )
177 {
178 if ( strlen ( pronunciation ) >= MAX_STRING_LEN )
179 {
180 PLogError ( "SR_Grammar_AddWordToSlot pronunciation : %s too long : Max %d", pronunciation, MAX_STRING_LEN - 1 );
181 return ( ESR_INVALID_ARGUMENT );
182 }
183 }
184 if ( tag != NULL )
185 {
186 if ( strlen ( tag ) >= MAX_STRING_LEN )
187 {
188 PLogError ( "SR_Grammar_AddWordToSlot tag : %s too long : Max %d", tag, MAX_STRING_LEN - 1 );
189 return ( ESR_INVALID_ARGUMENT );
190 }
191 }
192 #if 0
193 /* make sure to have the latest arbdata to add words, however since
194 the arbdata is known to be constant for all acoustic models we
195 have (ie for the different sample rates), then there is no need
196 to do this, it slows down addition anyways */
197 CA_Arbdata* ca_arbdata;
198 SR_AcousticModels* models;
199 impl->recognizer->getModels( impl->recognizer, &models);
200 ca_arbdata = models->GetArbdata(models);
201 CA_AttachArbdataToSyntax( impl->syntax , ca_arbdata);
202 #endif
203
204 /* yw HACK: Xanavi's application has bug. remove this check to let it work */
205 /* TODO: add this word to the semantic graph with associated script tag */
206 if (impl->vocabulary == NULL)
207 {
208 PLogError(L("ESR_INVALID_STATE"));
209 return ESR_INVALID_STATE;
210 }
211
212 /* tag may be NULL which means no script (no-op denoted by a simple semi-colon) */
213 if (!tag || !*tag)
214 tag = L(";");
215
216 if (!pronunciation || !(*pronunciation) || !LSTRCMP(pronunciation, L("NULL")))
217 {
218 vocab = (SR_Vocabulary*) impl->vocabulary;
219 CHKLOG(rc, vocab->getPronunciation(vocab, word, buffer, &len));
220 pronunciation = buffer;
221 }
222
223 /*
224 * 'buffer' contains a list of null-terminated pronunciations.
225 * Two consecutive null characters denote the end of the list.
226 *
227 * (In theory yes, but right now, only one pron is supported)
228 */
229 if (impl->eventLog != NULL)
230 {
231 CHKLOG(logrc, SR_EventLogTokenInt_BASIC(impl->eventLog, impl->logLevel, L("igrm"), (int)impl));
232 CHKLOG(logrc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("SLOT"), slot));
233 CHKLOG(logrc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("WORD"), word));
234 if (input_pronunciation)
235 CHKLOG(logrc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("PRON"), pronunciation));
236 else
237 CHKLOG(logrc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("GPRON"), pronunciation));
238 CHKLOG(logrc, SR_EventLogTokenInt_BASIC(impl->eventLog, impl->logLevel, L("WEIGHT"), weight));
239 CHKLOG(logrc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("TAG"), tag));
240 }
241
242 /* add word to syntax first */
243 /*
244 *
245 * if word already exists and pron is same (i.e. as if no action) returns FST_SUCCESS
246 * if word already exists and pron is different (e.g. read-rEd and read-red) returns FST_SUCCESS
247 * if word does not exist and no duplicate pron exists (homonyms not supported) returns FST_SUCCESS
248 * else FST_FAILED
249 */
250 ca_rc = CA_AddWordToSyntax(impl->syntax, slot, word, pronunciation, weight);
251 switch (ca_rc)
252 {
253 case FST_SUCCESS:
254 /* successful, now add word & tag to semgraph */
255 CHKLOG(rc, impl->semgraph->addWordToSlot(impl->semgraph, slot, word, tag, 1));
256 break;
257 case FST_SUCCESS_ON_OLD_WORD:
258 case FST_FAILED_ON_HOMOGRAPH:
259 /* successful, now add word & tag to semgraph */
260 CHKLOG(rc, impl->semgraph->addWordToSlot(impl->semgraph, slot, word, tag, 0));
261 break;
262 case FST_FAILED_ON_MEMORY:
263 rc = ESR_OUT_OF_MEMORY;
264 PLogError(ESR_rc2str(rc));
265 goto CLEANUP;
266 case FST_FAILED_ON_INVALID_ARGS:
267 rc = ESR_INVALID_ARGUMENT;
268 PLogError(ESR_rc2str(rc));
269 goto CLEANUP;
270 case FST_FAILED_ON_HOMONYM:
271 rc = ESR_NOT_SUPPORTED;
272 /* remove this message from product */
273 #if !defined(NDEBUG) || defined(_WIN32)
274 PLogError(L("%s: Homonym '%s' could not be added"), ESR_rc2str(rc), word);
275 #endif
276 goto CLEANUP;
277 default:
278 rc = ESR_INVALID_STATE;
279 PLogError(L("%s|%s|%s|ca_rc=%d"), word, pronunciation, ESR_rc2str(rc), ca_rc);
280 goto CLEANUP;
281 }
282
283 if (impl->eventLog != NULL && (impl->logLevel & OSI_LOG_LEVEL_ADDWD))
284 {
285 CHKLOG(logrc, SR_EventLogTokenInt_BASIC(impl->eventLog, impl->logLevel, L("caRC"), (int) ca_rc));
286 CHKLOG(logrc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("RSLT"), L("ok")));
287 CHKLOG(logrc, SR_EventLogEvent_BASIC(impl->eventLog, impl->logLevel, L("ESRaddWd")));
288 }
289 return rc;
290 CLEANUP:
291 PLogError(L("failed on |%s|%s|%s|\n"), slot, word, pronunciation);
292 if (impl->eventLog != NULL && (impl->logLevel & OSI_LOG_LEVEL_ADDWD))
293 {
294 CHKLOG(logrc, SR_EventLogTokenInt_BASIC(impl->eventLog, impl->logLevel, L("caRC"), (int) ca_rc));
295 CHKLOG(logrc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("RSLT"), L("err1")));
296 CHKLOG(logrc, SR_EventLogEvent_BASIC(impl->eventLog, impl->logLevel, L("ESRaddWd")));
297 }
298 return rc;
299 }
300
SR_Grammar_ResetAllSlots(SR_Grammar * self)301 ESR_ReturnCode SR_Grammar_ResetAllSlots(SR_Grammar* self)
302 {
303 ESR_ReturnCode rc, logrc;
304 int irc;
305 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
306
307 rc = impl->semgraph->reset(impl->semgraph);
308 if (rc == ESR_SUCCESS)
309 {
310 irc = CA_ResetSyntax(impl->syntax);
311 rc = irc ? ESR_INVALID_STATE : ESR_SUCCESS;
312 }
313
314 if (impl->eventLog != NULL)
315 {
316 CHKLOG(rc, SR_EventLogTokenInt_BASIC(impl->eventLog, impl->logLevel, L("igrm"), (int)impl));
317 if (rc == ESR_SUCCESS)
318 CHKLOG(logrc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("RSLT"), L("ok")));
319 else
320 CHKLOG(logrc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("RSLT"), L("fail")));
321 CHKLOG(logrc, SR_EventLogEvent_BASIC(impl->eventLog, impl->logLevel, L("ESRrstSlot")));
322 }
323 return ESR_SUCCESS;
324 CLEANUP:
325 return rc;
326 }
327
SR_Grammar_AddNametagToSlot(SR_Grammar * self,const LCHAR * slot,const SR_Nametag * nametag,int weight,const LCHAR * tag)328 ESR_ReturnCode SR_Grammar_AddNametagToSlot(SR_Grammar* self, const LCHAR* slot,
329 const SR_Nametag* nametag, int weight, const LCHAR* tag)
330 {
331 SR_NametagImpl* nametagImpl = (SR_NametagImpl*) nametag;
332 ESR_ReturnCode rc;
333
334 CHKLOG(rc, self->addWordToSlot(self, slot, nametagImpl->id, nametagImpl->value, weight, tag));
335 return ESR_SUCCESS;
336 CLEANUP:
337 return rc;
338 }
339
SR_Grammar_SetDispatchFunction(SR_Grammar * self,const LCHAR * functionName,void * userData,SR_GrammarDispatchFunction function)340 ESR_ReturnCode SR_Grammar_SetDispatchFunction(SR_Grammar* self, const LCHAR* functionName, void* userData, SR_GrammarDispatchFunction function)
341 {
342 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
343 ESR_ReturnCode rc;
344 SR_SemanticProcessorImpl* semprocImpl = (SR_SemanticProcessorImpl*) impl->semproc;
345
346 CHKLOG(rc, EP_RegisterFunction(semprocImpl->parser, functionName, userData, function));
347 return ESR_SUCCESS;
348 CLEANUP:
349 return rc;
350 }
351
SR_GrammarLoad(const LCHAR * grammar,SR_Grammar ** self)352 ESR_ReturnCode SR_GrammarLoad(const LCHAR* grammar, SR_Grammar** self)
353 {
354 SR_Grammar* Interface = NULL;
355 SR_GrammarImpl* impl;
356 LCHAR* tok;
357 ESR_ReturnCode rc;
358 LCHAR filename[P_PATH_MAX];
359 int addWords;
360
361
362 if (self == NULL)
363 {
364 PLogError(L("ESR_INVALID_ARGUMENT"));
365 return ESR_INVALID_ARGUMENT;
366 }
367 CHKLOG(rc, SR_Grammar_Create(&Interface));
368 impl = (SR_GrammarImpl*) Interface;
369
370 /**
371 * Our filename (referring to the grammar to load, may have associated grammar properties
372 * appended to the end of it. We need to split up the properties from the filename
373 * example:
374 * recog_nm/namesnnumsSC_dyn,addWords=2000 becomes
375 * filename: recog_nm/namesnnumsSC_dyn
376 * property: addWords=2000
377 */
378
379 /* init */
380 LSTRCPY(filename, grammar);
381 addWords = 0;
382
383 for (tok = strtok(filename, ","); tok; tok = strtok(NULL, ","))
384 {
385 if (LSTRSTR(tok, "addWords"))
386 {
387 addWords = atoi(LSTRCHR(tok, L('=')) + sizeof(LCHAR));
388 }
389 else if (tok != filename)
390 {
391 PLogError(L("UNKNOWN grammar load property %s"), tok);
392 rc = ESR_INVALID_STATE;
393 goto CLEANUP;
394 }
395 }
396
397 /**
398 * Based on the filename, determine if you are loading from image or loading from text files.
399 * If from image, then the filename will have extension .g2g. If from file, then only a basename
400 * will be provided (i.e. without extension)
401 */
402
403 impl->syntax = CA_AllocateSyntax();
404 if (impl->syntax == NULL)
405 {
406 rc = ESR_OUT_OF_MEMORY;
407 goto CLEANUP;
408 }
409
410 if (LSTRSTR(filename, L(".g2g")))
411 {
412 /* if the filename ends with .g2g, then we have a binary image */
413 if (CA_LoadSyntaxFromImage(impl->syntax, (LCHAR*) filename))
414 {
415 rc = ESR_READ_ERROR;
416 PLogError(L("ESR_READ_ERROR: Problem loading syntax from image"));
417 goto CLEANUP;
418 }
419 }
420 else
421 {
422 if (CA_LoadSyntaxAsExtensible(impl->syntax, (LCHAR*) filename, addWords))
423 {
424 rc = ESR_READ_ERROR;
425 PLogError(L("ESR_READ_ERROR: Problem loading syntax from text"));
426 goto CLEANUP;
427 }
428 }
429
430 /*
431 * Semantic Graph Loading
432 *
433 * - it was already created in Grammar_Create()
434 * - reuse the same input labels from the recognition context
435 * - load knows how to load from base filename or .g2g image
436 */
437 rc = impl->semgraph->load(impl->semgraph, impl->syntax->synx->olabels, filename, addWords);
438 if (rc != ESR_SUCCESS)
439 {
440 PLogError(L("%s: loading semgraph from image %s"), ESR_rc2str(rc), filename);
441 impl->semgraph = NULL;
442 goto CLEANUP;
443 }
444
445 *self = Interface;
446 if (impl->eventLog)
447 {
448 CHKLOG(rc, SR_EventLogTokenInt_BASIC(impl->eventLog, impl->logLevel, L("igrm"), (int)impl));
449 CHKLOG(rc, SR_EventLogToken_BASIC(impl->eventLog, impl->logLevel, L("name"), filename));
450 CHKLOG(rc, SR_EventLogEvent_BASIC(impl->eventLog, impl->logLevel, L("ESRldgrm")));
451 }
452
453 return ESR_SUCCESS;
454 CLEANUP:
455 if (Interface != NULL)
456 Interface->destroy(Interface);
457 *self = NULL;
458 return rc;
459 }
460
SR_Grammar_Save(SR_Grammar * self,const LCHAR * filename)461 ESR_ReturnCode SR_Grammar_Save(SR_Grammar* self, const LCHAR* filename)
462 {
463 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
464 int version_number = 2;
465
466 if (filename == NULL)
467 {
468 PLogError(L("ESR_INVALID_ARGUMENT"));
469 return ESR_INVALID_ARGUMENT;
470 }
471 if (CA_DumpSyntaxAsImage(impl->syntax, filename, version_number)) /* returns 1 on failure */
472 {
473 PLogError(L("ESR_INVALID_ARGUMENT"));
474 return ESR_INVALID_STATE;
475 }
476 if (SR_SemanticGraph_Save(impl->semgraph, filename, version_number) != ESR_SUCCESS)
477 {
478 PLogError(L("ESR_INVALID_ARGUMENT"));
479 return ESR_INVALID_STATE;
480 }
481
482 return ESR_SUCCESS;
483 }
484
SR_Grammar_SetParameter(SR_Grammar * self,const LCHAR * key,void * value)485 ESR_ReturnCode SR_Grammar_SetParameter(SR_Grammar* self, const LCHAR* key, void* value)
486 {
487 /*TODO: complete with logging*/
488 return ESR_NOT_IMPLEMENTED;
489 }
490
SR_Grammar_SetSize_tParameter(SR_Grammar * self,const LCHAR * key,size_t value)491 ESR_ReturnCode SR_Grammar_SetSize_tParameter(SR_Grammar* self, const LCHAR* key, size_t value)
492 {
493 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
494 size_t temp;
495 ESR_ReturnCode rc;
496
497 rc = impl->parameters->getSize_t(impl->parameters, key, &temp);
498 if (rc == ESR_SUCCESS)
499 {
500 if (temp == value)
501 return ESR_SUCCESS;
502 CHKLOG(rc, impl->parameters->removeAndFreeProperty(impl->parameters, key));
503 }
504 else if (rc != ESR_NO_MATCH_ERROR)
505 return rc;
506
507 CHKLOG(rc, impl->parameters->setSize_t(impl->parameters, key, value));
508 return ESR_SUCCESS;
509 CLEANUP:
510 return rc;
511 }
512
SR_Grammar_GetParameter(SR_Grammar * self,const LCHAR * key,void ** value)513 ESR_ReturnCode SR_Grammar_GetParameter(SR_Grammar* self, const LCHAR* key, void** value)
514 {
515
516 /*TODO: complete with logging*/
517 return ESR_NOT_IMPLEMENTED;
518 }
519
SR_Grammar_GetSize_tParameter(SR_Grammar * self,const LCHAR * key,size_t * value)520 ESR_ReturnCode SR_Grammar_GetSize_tParameter(SR_Grammar* self, const LCHAR* key, size_t* value)
521 {
522 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
523 ESR_ReturnCode rc;
524
525 if (!LSTRCMP(key, "locale"))
526 {
527 ESR_Locale locale;
528 rc = SR_VocabularyGetLanguage(impl->vocabulary, &locale);
529 if (rc != ESR_SUCCESS)
530 return rc;
531
532 *value = locale;
533 return ESR_SUCCESS;
534 }
535 else
536 {
537 rc = impl->parameters->getSize_t(impl->parameters, key, value);
538 if (rc == ESR_NO_MATCH_ERROR)
539 {
540 CHKLOG(rc, ESR_SessionGetSize_t(key, value));
541 return ESR_SUCCESS;
542 }
543 if (rc != ESR_SUCCESS)
544 {
545 PLogError(ESR_rc2str(rc));
546 return rc;
547 }
548 return ESR_SUCCESS;
549 }
550 CLEANUP:
551 return rc;
552 }
553
SR_Grammar_Destroy(SR_Grammar * self)554 ESR_ReturnCode SR_Grammar_Destroy(SR_Grammar* self)
555 {
556 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
557 ESR_ReturnCode rc;
558
559 if (impl->parameters != NULL)
560 {
561 CHKLOG(rc, impl->parameters->destroy(impl->parameters));
562 impl->parameters = NULL;
563 }
564
565 if (impl->syntax != NULL)
566 {
567 CA_FreeSyntax(impl->syntax);
568 impl->syntax = NULL;
569 }
570
571 if (impl->semgraph != NULL)
572 {
573 CHKLOG(rc, impl->semgraph->unload(impl->semgraph));
574 CHKLOG(rc, impl->semgraph->destroy(impl->semgraph));
575 impl->semgraph = NULL;
576 }
577
578 if (impl->semproc != NULL)
579 {
580 CHKLOG(rc, impl->semproc->destroy(impl->semproc));
581 impl->semproc = NULL;
582 }
583
584 if (impl->eventLog)
585 {
586 CHKLOG(rc, SR_EventLogTokenInt_BASIC(impl->eventLog, impl->logLevel, L("igrm"), (int)impl));
587 CHKLOG(rc, SR_EventLogEvent_BASIC(impl->eventLog, impl->logLevel, L("ESRklgrm")));
588 }
589
590 FREE(self);
591 return ESR_SUCCESS;
592 CLEANUP:
593 return rc;
594 }
595
SR_Grammar_SetupRecognizer(SR_Grammar * self,SR_Recognizer * recognizer)596 ESR_ReturnCode SR_Grammar_SetupRecognizer(SR_Grammar* self, SR_Recognizer* recognizer)
597 {
598 ESR_ReturnCode rc;
599 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
600 CA_Arbdata* ca_arbdata;
601 SR_AcousticModels* models = NULL;
602
603 if (impl == NULL || recognizer == NULL)
604 {
605 PLogError(L("ESR_INVALID_ARGUMENT"));
606 return ESR_INVALID_ARGUMENT;
607 }
608 impl->recognizer = recognizer;
609 recognizer->setWordAdditionCeiling( recognizer, self);
610
611 rc = recognizer->getModels( recognizer, &models);
612 if(rc != ESR_SUCCESS || models == NULL) {
613 impl->recognizer = NULL;
614 CA_AttachArbdataToSyntax( impl->syntax, NULL);
615 return ESR_INVALID_STATE;
616 }
617 ca_arbdata = (CA_Arbdata*)(models->getArbdata( models));
618 rc = CA_AttachArbdataToSyntax( impl->syntax, ca_arbdata);
619 if(rc != 0)
620 return ESR_INVALID_STATE;
621 return ESR_SUCCESS;
622 }
623
SR_Grammar_UnsetupRecognizer(SR_Grammar * self)624 ESR_ReturnCode SR_Grammar_UnsetupRecognizer(SR_Grammar* self)
625 {
626 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
627 if(impl == NULL) return ESR_INVALID_ARGUMENT;
628 impl->recognizer = NULL;
629 CA_AttachArbdataToSyntax( impl->syntax, NULL);
630 return ESR_SUCCESS;
631 }
632
SR_Grammar_SetupVocabulary(SR_Grammar * self,SR_Vocabulary * vocabulary)633 SREC_GRAMMAR_API ESR_ReturnCode SR_Grammar_SetupVocabulary(SR_Grammar *self, SR_Vocabulary *vocabulary)
634 {
635 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
636
637 if (vocabulary == NULL)
638 {
639 PLogError(L("ESR_INVALID_ARGUMENT"));
640 return ESR_INVALID_ARGUMENT;
641 }
642 impl->vocabulary = vocabulary;
643 return ESR_SUCCESS;
644 }
645
SR_Grammar_CheckParse(SR_Grammar * self,const LCHAR * transcription,SR_SemanticResult ** result,size_t * resultCount)646 ESR_ReturnCode SR_Grammar_CheckParse(SR_Grammar* self, const LCHAR* transcription, SR_SemanticResult** result, size_t* resultCount)
647 {
648 ESR_ReturnCode rc;
649 SR_GrammarImpl* impl = (SR_GrammarImpl*) self;
650 size_t resultCountIn = *resultCount;
651
652 if (transcription == NULL)
653 {
654 PLogError(L("ESR_INVALID_ARGUMENT"));
655 return ESR_INVALID_ARGUMENT;
656 }
657
658 /* NULL for special implementation when CheckParse is called by application that does not know
659 about the hidden data structure SR_SemanticResult */
660 if (result == NULL)
661 {
662 if (CA_CheckTranscription(impl->syntax, transcription, 0) == 0)
663 *resultCount = 1;
664 else
665 *resultCount = 0;
666 return ESR_SUCCESS;
667 }
668 rc = impl->semproc->checkParse(impl->semproc, impl->semgraph, transcription, result, resultCount);
669 if (*resultCount == 0)
670 {
671 /* get the literal that did parse from the text_parser.c code */
672 char copy_of_trans[512];
673 strcpy(copy_of_trans, transcription);
674 *resultCount = resultCountIn;
675 if (CA_CheckTranscription(impl->syntax, (LCHAR*)copy_of_trans, 0) == 0)
676 rc = impl->semproc->checkParse(impl->semproc, impl->semgraph, copy_of_trans, result, resultCount);
677 }
678 return rc;
679 }
680
681 #define DISABLEcostdata 8192
682
SR_GrammarAllowOnly(SR_Grammar * self,const char * transcription)683 ESR_ReturnCode SR_GrammarAllowOnly(SR_Grammar* self, const char* transcription)
684 {
685 char copy_of[512], *word;
686 int i, j;
687 wordID wdids[32], nw = 0;
688 SR_GrammarImpl* impl = (SR_GrammarImpl*)self;
689 CA_Syntax* ca_syntax = impl->syntax;
690 srec_context* fst = ca_syntax->synx;
691 ESR_ReturnCode rc = ESR_SUCCESS;
692
693 strcpy(copy_of, transcription);
694
695 for (word = strtok(copy_of, " "); word; nw++, word = strtok(NULL, " "))
696 {
697 wdids[nw] = wordmap_find_index(fst->olabels, word);
698 if (wdids[nw] == MAXwordID)
699 rc = ESR_NO_MATCH_ERROR;
700 }
701
702 for (i = 0; i < fst->num_arcs; i++)
703 {
704 wordID wdid = fst->FSMarc_list[i].olabel;
705 if (wdid < EPSILON_OFFSET) ;
706 else if (wdid == fst->beg_silence_word) ;
707 else if (wdid == fst->end_silence_word) ;
708 else
709 {
710 for (j = nw; --j >= 0;)
711 if (wdid == wdids[j]) break;
712 if (j < 0)
713 {
714 fst->FSMarc_list[i].cost |= DISABLEcostdata; /* disable this arc */
715 }
716 else
717 {
718 /* pfprintf(PSTDOUT, "enabling arc %d for %d %s\n",
719 i, wdid, transcription); */
720 fst->FSMarc_list[i].cost &= ~(DISABLEcostdata); /* enable this arc */
721 }
722 }
723 }
724 /* added, this way we prevent more failures due to dead ends */
725 for (; ;)
726 {
727 FSMarc* arc;
728 arcID j, counter = 0;
729 nodeID node;
730 costdata mincost;
731
732 for (i = 0; i < fst->num_arcs; i++)
733 {
734 if (fst->FSMarc_list[i].cost < DISABLEcostdata)
735 {
736 node = fst->FSMarc_list[i].to_node;
737 if (node == fst->end_node) continue;
738 mincost = DISABLEcostdata;
739 for (j = fst->FSMnode_list[node].un_ptr.first_next_arc; j != MAXarcID; j = arc->linkl_next_arc)
740 {
741 arc = &fst->FSMarc_list[j];
742 if (arc->cost < mincost) mincost = arc->cost;
743 }
744 if (mincost >= DISABLEcostdata)
745 {
746 fst->FSMarc_list[i].cost |= DISABLEcostdata;
747 counter++;
748 }
749 }
750 }
751 if (counter == 0) break;
752 }
753
754 return rc;
755 }
756
SR_GrammarAllowAll(SR_Grammar * self)757 ESR_ReturnCode SR_GrammarAllowAll(SR_Grammar* self)
758 {
759 int i;
760 SR_GrammarImpl* impl = (SR_GrammarImpl*)self;
761 CA_Syntax* ca_syntax = impl->syntax;
762 srec_context* fst = ca_syntax->synx;
763 ESR_ReturnCode rc = ESR_SUCCESS;
764
765 for (i = 0; i < fst->num_arcs; i++)
766 {
767 fst->FSMarc_list[i].cost &= ~(DISABLEcostdata); /* enable this arc */
768 }
769 return rc;
770 }
771
772