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