Home | History | Annotate | Download | only in src
      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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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