• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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