Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1325 lines
52 KiB

  1. /*******************************************************************************
  2. * morph.cpp *
  3. *-----------*
  4. * Description:
  5. * This is the implementation of the CSMorph class, which attempts to find
  6. * pronunciations for morphologcical variants (which are not in the lexicon) of
  7. * root words (which are in the lexicon).
  8. *-------------------------------------------------------------------------------
  9. * Created By: AH, based partly on code by MC Date: 08/16/99
  10. * Copyright (C) 1999 Microsoft Corporation
  11. * All Rights Reserved
  12. *
  13. *******************************************************************************/
  14. // Additional includes...
  15. #include "stdafx.h"
  16. #include "morph.h"
  17. #include "spttsengdebug.h"
  18. /*****************************************************************************
  19. * CSMorph::CSMorph *
  20. *------------------*
  21. * Description: Constructor - just sets the Master Lexicon pointer...
  22. *
  23. ********************************************************************** AH ***/
  24. CSMorph::CSMorph( ISpLexicon *pMasterLex, HRESULT *phr )
  25. {
  26. SPDBG_FUNC( "CSMorph::CSMorph" );
  27. SPDBG_ASSERT( phr != NULL );
  28. m_pMasterLex = pMasterLex;
  29. // Initialize the SuffixInfoTable - obtain lock to make sure this only happens once...
  30. g_SuffixInfoTableCritSec.Lock();
  31. if (!SuffixInfoTableInitialized)
  32. {
  33. CComPtr<ISpPhoneConverter> pPhoneConv;
  34. *phr = SpCreatePhoneConverter(1033, NULL, NULL, &pPhoneConv);
  35. for (int i = 0; i < sp_countof(g_SuffixInfoTable); i++)
  36. {
  37. *phr = pPhoneConv->PhoneToId(g_SuffixInfoTable[i].SuffixString, g_SuffixInfoTable[i].SuffixString);
  38. if ( FAILED( *phr ) )
  39. {
  40. break;
  41. }
  42. }
  43. if (SUCCEEDED(*phr))
  44. {
  45. *phr = pPhoneConv->PhoneToId(g_phonS, g_phonS);
  46. if (SUCCEEDED(*phr))
  47. {
  48. *phr = pPhoneConv->PhoneToId(g_phonZ, g_phonZ);
  49. if (SUCCEEDED(*phr))
  50. {
  51. *phr = pPhoneConv->PhoneToId(g_phonAXz, g_phonAXz);
  52. if (SUCCEEDED(*phr))
  53. {
  54. *phr = pPhoneConv->PhoneToId(g_phonT, g_phonT);
  55. if (SUCCEEDED(*phr))
  56. {
  57. *phr = pPhoneConv->PhoneToId(g_phonD, g_phonD);
  58. if (SUCCEEDED(*phr))
  59. {
  60. *phr = pPhoneConv->PhoneToId(g_phonAXd, g_phonAXd);
  61. if (SUCCEEDED(*phr))
  62. {
  63. *phr = pPhoneConv->PhoneToId(g_phonAXl, g_phonAXl);
  64. if ( SUCCEEDED( *phr ) )
  65. {
  66. *phr = pPhoneConv->PhoneToId(g_phonIY, g_phonIY);
  67. if ( SUCCEEDED( *phr ) )
  68. {
  69. *phr = pPhoneConv->PhoneToId(g_phonL, g_phonL);
  70. }
  71. }
  72. }
  73. }
  74. }
  75. }
  76. }
  77. }
  78. }
  79. }
  80. if (SUCCEEDED(*phr))
  81. {
  82. SuffixInfoTableInitialized = true;
  83. }
  84. g_SuffixInfoTableCritSec.Unlock();
  85. } /* CSMorph::CSMorph */
  86. /*****************************************************************************
  87. * CSMorph::DoSuffixMorph *
  88. *------------------------*
  89. * Description: This is the only interface function of CSMorph - it
  90. * takes the same arguments as a GetPronunciations() call, and does
  91. * basically the same thing.
  92. *
  93. ********************************************************************** AH ***/
  94. HRESULT CSMorph::DoSuffixMorph( const WCHAR *pwWord, WCHAR *pwRoot, LANGID LangID, DWORD dwFlags,
  95. SPWORDPRONUNCIATIONLIST *pWordPronunciationList )
  96. {
  97. SPDBG_FUNC( "CSMorph::DoSuffixMorph" );
  98. HRESULT hr = S_OK;
  99. SUFFIX_TYPE suffixCode;
  100. WCHAR TargWord[SP_MAX_WORD_LENGTH] = {0};
  101. long RootLen = 0;
  102. CSuffixList SuffixList;
  103. bool bGotMorph, bNotDone, bLTS;
  104. if ( !pwWord || !pWordPronunciationList )
  105. {
  106. hr = E_POINTER;
  107. }
  108. else if ( SP_IS_BAD_WRITE_PTR( pwRoot ) ||
  109. SPIsBadLexWord(pwWord) ||
  110. SPIsBadWordPronunciationList(pWordPronunciationList) ||
  111. LangID != 1033)
  112. {
  113. hr = E_INVALIDARG;
  114. }
  115. if (SUCCEEDED(hr))
  116. {
  117. // INITIALIZE locals...
  118. suffixCode = NO_MATCH;
  119. bGotMorph = false;
  120. bNotDone = true;
  121. bLTS = false;
  122. wcscpy( TargWord, pwWord ); // Copy orth string...
  123. _wcsupr( TargWord ); // ...and convert to uppercase
  124. RootLen = wcslen( TargWord );
  125. // Keep trying to match another suffix until a root word is matched in the lexicon, or
  126. // until some error condition is reached - no more suffix matches, etc.
  127. while ( !bGotMorph && bNotDone )
  128. {
  129. // Try to match a suffix...
  130. suffixCode = MatchSuffix( TargWord, &RootLen );
  131. // ...add it to the suffix list...
  132. if (suffixCode != NO_MATCH)
  133. {
  134. SuffixList.AddHead(&g_SuffixInfoTable[suffixCode]);
  135. }
  136. // ...and then behave appropriately.
  137. switch (suffixCode)
  138. {
  139. //------------------------------------------------------------
  140. // S - two special cases for +s suffix...
  141. //------------------------------------------------------------
  142. case S_SUFFIX:
  143. //--- Don't strip an S if it is preceded by another S...
  144. if ( TargWord[RootLen-1] == L'S' )
  145. {
  146. bNotDone = false;
  147. RootLen++;
  148. SuffixList.RemoveHead();
  149. if (!SuffixList.IsEmpty() && (dwFlags & eLEXTYPE_PRIVATE2))
  150. {
  151. hr = LTSLookup(pwWord, RootLen, pWordPronunciationList);
  152. if (SUCCEEDED(hr))
  153. {
  154. bLTS = true;
  155. bGotMorph = true;
  156. }
  157. }
  158. else
  159. {
  160. hr = SPERR_NOT_IN_LEX;
  161. }
  162. break;
  163. }
  164. hr = LexLookup(TargWord, RootLen, dwFlags, pWordPronunciationList);
  165. if ( SUCCEEDED(hr) )
  166. {
  167. bGotMorph = true;
  168. }
  169. else if ( hr != SPERR_NOT_IN_LEX )
  170. {
  171. bNotDone = false;
  172. }
  173. else if ( TargWord[RootLen - 1] == L'E' )
  174. {
  175. hr = CheckYtoIEMutation(TargWord, RootLen, dwFlags, pWordPronunciationList);
  176. if (SUCCEEDED(hr))
  177. {
  178. bGotMorph = true;
  179. }
  180. else if (hr != SPERR_NOT_IN_LEX)
  181. {
  182. bNotDone = false;
  183. }
  184. else
  185. {
  186. hr = LexLookup(TargWord, RootLen - 1, dwFlags, pWordPronunciationList);
  187. if (SUCCEEDED(hr))
  188. {
  189. bGotMorph = true;
  190. }
  191. else if (hr != SPERR_NOT_IN_LEX)
  192. {
  193. bNotDone = false;
  194. }
  195. }
  196. }
  197. break;
  198. //------------------------------------------------------------
  199. // ICALLY_SUFFIX - special case, RAID #3201
  200. //------------------------------------------------------------
  201. case ICALLY_SUFFIX:
  202. hr = LexLookup( TargWord, RootLen + 2, dwFlags, pWordPronunciationList );
  203. if ( SUCCEEDED( hr ) )
  204. {
  205. bGotMorph = true;
  206. }
  207. else if ( hr != SPERR_NOT_IN_LEX )
  208. {
  209. bNotDone = false;
  210. }
  211. else
  212. {
  213. RootLen += 2;
  214. }
  215. break;
  216. //-------------------------------------------------------------
  217. // ILY_SUFFIX - special case, RAID #6571
  218. //-------------------------------------------------------------
  219. case ILY_SUFFIX:
  220. hr = CheckForMissingY( TargWord, RootLen, dwFlags, pWordPronunciationList );
  221. if ( SUCCEEDED( hr ) )
  222. {
  223. RootLen++;
  224. bGotMorph = true;
  225. }
  226. else if ( hr != SPERR_NOT_IN_LEX )
  227. {
  228. bNotDone = false;
  229. }
  230. break;
  231. //------------------------------------------------------------
  232. // ICISM_SUFFIX, ICIZE_SUFFIX - special case, RAID #6492
  233. //------------------------------------------------------------
  234. case ICISM_SUFFIX:
  235. case ICIZE_SUFFIX:
  236. hr = LexLookup( TargWord, RootLen + 2, dwFlags, pWordPronunciationList );
  237. if ( SUCCEEDED( hr ) )
  238. {
  239. bGotMorph = true;
  240. for ( SPWORDPRONUNCIATION* pIterator = pWordPronunciationList->pFirstWordPronunciation;
  241. pIterator; pIterator = pIterator->pNextWordPronunciation )
  242. {
  243. pIterator->szPronunciation[ wcslen( pIterator->szPronunciation ) - 1 ] = g_phonS[0];
  244. }
  245. }
  246. else if ( hr != SPERR_NOT_IN_LEX )
  247. {
  248. bNotDone = false;
  249. }
  250. else
  251. {
  252. RootLen += 2;
  253. }
  254. break;
  255. //------------------------------------------------------------
  256. // NO_MATCH
  257. //------------------------------------------------------------
  258. case NO_MATCH:
  259. bNotDone = false;
  260. if (!SuffixList.IsEmpty() && (dwFlags & eLEXTYPE_PRIVATE2))
  261. {
  262. hr = LTSLookup(pwWord, RootLen, pWordPronunciationList);
  263. if (SUCCEEDED(hr))
  264. {
  265. bLTS = true;
  266. bGotMorph = true;
  267. }
  268. }
  269. else
  270. {
  271. hr = SPERR_NOT_IN_LEX;
  272. }
  273. break;
  274. //----------------------------------------------------------------
  275. // ABLY - special case (for probably, etc.) RAID #3168
  276. //----------------------------------------------------------------
  277. case ABLY_SUFFIX:
  278. hr = CheckAbleMutation( TargWord, RootLen, dwFlags, pWordPronunciationList );
  279. if ( SUCCEEDED( hr ) )
  280. {
  281. for ( SPWORDPRONUNCIATION *pIterator = pWordPronunciationList->pFirstWordPronunciation;
  282. pIterator; pIterator = pIterator->pNextWordPronunciation )
  283. {
  284. if ( wcslen( pIterator->szPronunciation ) > 2 &&
  285. wcscmp( ( pIterator->szPronunciation +
  286. ( wcslen( pIterator->szPronunciation ) - 2 ) ),
  287. g_phonAXl ) == 0 )
  288. {
  289. wcscpy( ( pIterator->szPronunciation +
  290. ( wcslen( pIterator->szPronunciation ) - 2 ) ),
  291. g_phonL );
  292. }
  293. }
  294. SuffixList.RemoveHead();
  295. SuffixList.AddHead( &g_SuffixInfoTable[Y_SUFFIX] );
  296. bGotMorph = true;
  297. break;
  298. }
  299. else if ( hr != SPERR_NOT_IN_LEX )
  300. {
  301. bNotDone = false;
  302. break;
  303. }
  304. //--- else no break - just continue on to default behavior...
  305. //------------------------------------------------------------
  306. // ALL OTHER SUFFIXES
  307. //------------------------------------------------------------
  308. default:
  309. // If applicable, try looking up the root with an added e first - this prevents things like
  310. // "taping" coming out as "tapping" rather than "tape +ing"
  311. // FIX BUG #2301, #3649 - ONLY Try with added e if the root does not end in o, e, w, or y
  312. if ( (SUCCEEDED(hr) || hr == SPERR_NOT_IN_LEX) &&
  313. (g_SuffixInfoTable[suffixCode].dwMorphSpecialCaseFlags & eCheckForMissingE) &&
  314. TargWord[RootLen-1] != L'O' &&
  315. ( TargWord[RootLen-1] != L'E' || suffixCode == ED_SUFFIX ) &&
  316. TargWord[RootLen-1] != L'W' &&
  317. TargWord[RootLen-1] != L'Y' )
  318. {
  319. hr = CheckForMissingE(TargWord, RootLen, dwFlags, pWordPronunciationList);
  320. if ( SUCCEEDED(hr) )
  321. {
  322. RootLen++;
  323. bGotMorph = true;
  324. break;
  325. }
  326. else if ( hr != SPERR_NOT_IN_LEX )
  327. {
  328. bNotDone = false;
  329. break;
  330. }
  331. }
  332. // Try looking up the root...
  333. if ( (SUCCEEDED(hr) || hr == SPERR_NOT_IN_LEX) )
  334. {
  335. hr = LexLookup(TargWord, RootLen, dwFlags, pWordPronunciationList);
  336. if ( SUCCEEDED(hr) )
  337. {
  338. bGotMorph = true;
  339. break;
  340. }
  341. else if ( hr != SPERR_NOT_IN_LEX )
  342. {
  343. bNotDone = false;
  344. break;
  345. }
  346. }
  347. // If previous lookups failed, try looking up the root with a 'y' in place of the final 'i'...
  348. if ( (SUCCEEDED(hr) || hr == SPERR_NOT_IN_LEX) &&
  349. (g_SuffixInfoTable[suffixCode].dwMorphSpecialCaseFlags & eCheckYtoIMutation) )
  350. {
  351. hr = CheckYtoIMutation(TargWord, RootLen, dwFlags, pWordPronunciationList);
  352. if ( SUCCEEDED(hr) )
  353. {
  354. bGotMorph = true;
  355. break;
  356. }
  357. else if ( hr != SPERR_NOT_IN_LEX )
  358. {
  359. bNotDone = false;
  360. break;
  361. }
  362. }
  363. // If previous lookups failed, try looking up the root with an undoubled ending...
  364. if ( (SUCCEEDED(hr) || hr == SPERR_NOT_IN_LEX) &&
  365. (g_SuffixInfoTable[suffixCode].dwMorphSpecialCaseFlags & eCheckDoubledMutation) )
  366. {
  367. hr = CheckDoubledMutation(TargWord, RootLen, dwFlags, pWordPronunciationList);
  368. if ( SUCCEEDED(hr) )
  369. {
  370. RootLen--;
  371. bGotMorph = true;
  372. break;
  373. }
  374. else if ( hr != SPERR_NOT_IN_LEX )
  375. {
  376. bNotDone = false;
  377. break;
  378. }
  379. }
  380. //--- If previous lookups failed, try looking up the root with an added 'l'
  381. if ( ( SUCCEEDED( hr ) || hr == SPERR_NOT_IN_LEX ) &&
  382. ( g_SuffixInfoTable[suffixCode].dwMorphSpecialCaseFlags & eCheckForMissingL ) )
  383. {
  384. hr = CheckForMissingL( TargWord, RootLen, dwFlags, pWordPronunciationList );
  385. if ( SUCCEEDED( hr ) )
  386. {
  387. RootLen++;
  388. bGotMorph = true;
  389. break;
  390. }
  391. else if ( hr != SPERR_NOT_IN_LEX )
  392. {
  393. bNotDone = false;
  394. break;
  395. }
  396. }
  397. break;
  398. } // switch (SuffixCode)
  399. } // while ( !bGotMorph && bNotDone )
  400. if ( SUCCEEDED(hr) && bGotMorph )
  401. {
  402. if (!SuffixList.IsEmpty())
  403. {
  404. //--- Copy found root word into out parameter, pwRoot
  405. wcsncpy( pwRoot, TargWord, RootLen );
  406. //--- Log info to debug file
  407. TTSDBG_LOGMORPHOLOGY( pwRoot, SuffixList, STREAM_MORPHOLOGY );
  408. if (bLTS)
  409. {
  410. hr = AccumulateSuffixes_LTS( &SuffixList, pWordPronunciationList );
  411. }
  412. else
  413. {
  414. hr = AccumulateSuffixes( &SuffixList, pWordPronunciationList );
  415. }
  416. }
  417. }
  418. }
  419. return hr;
  420. } /* CSMorph::DoSuffixMorph */
  421. /*****************************************************************************
  422. * CSMorph::MatchSuffix *
  423. *----------------------*
  424. * Description: This function attempts to match a suffix in TargWord.
  425. *
  426. ********************************************************************** AH ***/
  427. SUFFIX_TYPE CSMorph::MatchSuffix( WCHAR *TargWord, long *RootLen )
  428. {
  429. SPDBG_FUNC( "CSMorph::MatchSuffix" );
  430. SUFFIX_TYPE suffixCode = NO_MATCH;
  431. long RootEnd = *RootLen - 1;
  432. const WCHAR *pTempSuffix = NULL;
  433. for (int i = 0; i < sp_countof(g_SuffixTable); i++)
  434. {
  435. pTempSuffix = g_SuffixTable[i].Orth;
  436. while ( (TargWord[RootEnd] == *pTempSuffix) && (RootEnd > 1) && (suffixCode == NO_MATCH) )
  437. {
  438. RootEnd--;
  439. pTempSuffix++;
  440. if ( *pTempSuffix == '\0' )
  441. {
  442. suffixCode = g_SuffixTable[i].Type;
  443. }
  444. }
  445. if (suffixCode != NO_MATCH)
  446. {
  447. *RootLen = RootEnd + 1;
  448. break;
  449. }
  450. else
  451. {
  452. RootEnd = *RootLen - 1;
  453. }
  454. }
  455. return suffixCode;
  456. } /* CSMorph::MatchSuffix */
  457. /*****************************************************************************
  458. * CSMorph::LexLookup *
  459. *--------------------*
  460. * Description: Try to look up the hypothesized root in the lexicon.
  461. *
  462. ********************************************************************** MC ***/
  463. HRESULT CSMorph::LexLookup( const WCHAR *pOrth, long length, DWORD dwFlags,
  464. SPWORDPRONUNCIATIONLIST *pWordPronunciationList )
  465. {
  466. SPDBG_FUNC( "CSMorph::LexLookup" );
  467. WCHAR targRoot[SP_MAX_WORD_LENGTH];
  468. memset (targRoot, 0, SP_MAX_WORD_LENGTH * sizeof(WCHAR));
  469. HRESULT hr = SPERR_NOT_IN_LEX;
  470. //---------------------------------
  471. // Copy root candidate only...
  472. //---------------------------------
  473. for( long i = 0; i < length; i++ )
  474. {
  475. targRoot[i] = pOrth[i];
  476. }
  477. targRoot[i] = 0; // Delimiter
  478. //---------------------------------
  479. // ...and look it up
  480. //---------------------------------
  481. if (dwFlags & eLEXTYPE_USER)
  482. {
  483. hr = m_pMasterLex->GetPronunciations( targRoot, 1033, eLEXTYPE_USER, pWordPronunciationList );
  484. }
  485. if ((hr == SPERR_NOT_IN_LEX) && (dwFlags & eLEXTYPE_APP))
  486. {
  487. hr = m_pMasterLex->GetPronunciations( targRoot, 1033, eLEXTYPE_APP, pWordPronunciationList );
  488. }
  489. if ((hr == SPERR_NOT_IN_LEX) && (dwFlags & eLEXTYPE_PRIVATE1))
  490. {
  491. hr = m_pMasterLex->GetPronunciations( targRoot, 1033, eLEXTYPE_PRIVATE1, pWordPronunciationList );
  492. }
  493. return hr;
  494. } /* CSMorph::LexLookup */
  495. /*****************************************************************************
  496. * CSMorph::LTSLookup *
  497. *--------------------*
  498. * Description: Try to get a pronunciation for the hypothesized root from
  499. * the LTS lexicon...
  500. *
  501. ********************************************************************** AH ***/
  502. HRESULT CSMorph::LTSLookup( const WCHAR *pOrth, long length,
  503. SPWORDPRONUNCIATIONLIST *pWordPronunciationList )
  504. {
  505. SPDBG_FUNC( "CSMorph::LTSLookup" );
  506. WCHAR targRoot[SP_MAX_WORD_LENGTH];
  507. memset(targRoot, 0, SP_MAX_WORD_LENGTH * sizeof(WCHAR));
  508. HRESULT hr = S_OK;
  509. //-------------------------------
  510. // Copy root candidate only...
  511. //-------------------------------
  512. for ( long i = 0; i < length; i++ )
  513. {
  514. targRoot[i] = pOrth[i];
  515. }
  516. targRoot[i] = 0;
  517. //-------------------------------
  518. // ...and look it up
  519. //-------------------------------
  520. hr = m_pMasterLex->GetPronunciations( targRoot, 1033, eLEXTYPE_PRIVATE2, pWordPronunciationList );
  521. return hr;
  522. } /* CSMorph::LTSLookup */
  523. /*****************************************************************************
  524. * CSMorph::AccumulateSuffixes *
  525. *-----------------------------*
  526. * Description: Append pronunciations of all the suffixes to the
  527. * retrieved pronunciation of the root word.
  528. *
  529. * First attempt a very strict derivation, where each suffix appended has
  530. * a "To" part of speech which matches the part of speech of the current
  531. * state of the entire word. Ex:
  532. *
  533. * govern (Verb) + ment (Verb -> Noun) + s (Noun -> Noun) -> governments (Noun)
  534. *
  535. * If this fails, just accumulate all the pronunciations, and use all of
  536. * the "To" parts of speech of the last suffix. Ex:
  537. *
  538. * cat (Noun) + ing (Verb -> Verb, Verb -> Adj, Verb -> Noun) -> catting (Verb, Adj, Noun)
  539. *
  540. ********************************************************************** AH ***/
  541. HRESULT CSMorph::AccumulateSuffixes( CSuffixList *pSuffixList, SPWORDPRONUNCIATIONLIST *pWordPronunciationList )
  542. {
  543. /********** Local Variable Declarations **********/
  544. SPWORDPRONUNCIATIONLIST *pTempWordPronunciationList;
  545. SPWORDPRONUNCIATION *pWordPronIterator = NULL, *pTempWordPronunciation = NULL;
  546. SPLISTPOS ListPos;
  547. SUFFIXPRON_INFO *SuffixPronInfo;
  548. ENGPARTOFSPEECH ActivePos[NUM_POS] = {MS_Unknown}, FinalPos[NUM_POS] = {MS_Unknown};
  549. WCHAR pBuffer[SP_MAX_PRON_LENGTH], pSuffixString[10];
  550. DWORD dwTotalSize = 0, dwNumActivePos = 0, dwNumFinalPos = 0;
  551. HRESULT hr = S_OK;
  552. bool bPOSMatch = false, bDerivedAWord = false;
  553. /********** Allocate enough space for the modified pronunciations **********/
  554. dwTotalSize = sizeof(SPWORDPRONUNCIATIONLIST) +
  555. (NUM_POS * (sizeof(SPWORDPRONUNCIATION) + (SP_MAX_PRON_LENGTH * sizeof(WCHAR))));
  556. pTempWordPronunciationList = new SPWORDPRONUNCIATIONLIST;
  557. if ( !pTempWordPronunciationList )
  558. {
  559. hr = E_OUTOFMEMORY;
  560. }
  561. if ( SUCCEEDED( hr ) )
  562. {
  563. memset(pTempWordPronunciationList, 0, sizeof(SPWORDPRONUNCIATIONLIST));
  564. hr = ReallocSPWORDPRONList( pTempWordPronunciationList, dwTotalSize );
  565. }
  566. /************************************
  567. * First Attempt Strict Derivation *
  568. ************************************/
  569. /********** Set Initial Values of prounciation list iterators **********/
  570. if (SUCCEEDED(hr))
  571. {
  572. pWordPronIterator = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation;
  573. pTempWordPronunciation = pTempWordPronunciationList->pFirstWordPronunciation;
  574. }
  575. /********** Iterate over pWordPronunciationList **********/
  576. while (SUCCEEDED(hr) && pWordPronIterator)
  577. {
  578. // Store the pronunciation in a buffer...
  579. wcscpy(pBuffer, pWordPronIterator->szPronunciation);
  580. // Initialize variables which are local to the next loop...
  581. bPOSMatch = true;
  582. ListPos = pSuffixList->GetHeadPosition();
  583. ActivePos[0] = (ENGPARTOFSPEECH)pWordPronIterator->ePartOfSpeech;
  584. dwNumActivePos = 1;
  585. /********** Iterate over the SuffixList **********/
  586. while ( SUCCEEDED(hr) && ListPos && bPOSMatch )
  587. {
  588. // Initialize variables which are local to the next loop...
  589. bPOSMatch = false;
  590. SuffixPronInfo = pSuffixList->GetNext( ListPos );
  591. wcsncpy(pSuffixString, SuffixPronInfo->SuffixString,10);
  592. pSuffixString[9] = L'\0';
  593. ENGPARTOFSPEECH NextActivePos[NUM_POS] = {MS_Unknown};
  594. DWORD dwNumNextActivePos = 0;
  595. /********** Iterate over the active parts of speech **********/
  596. for (DWORD j = 0; j < dwNumActivePos; j++)
  597. {
  598. /********** Iterate over the possible conversions of each suffix **********/
  599. for (short i = 0; i < SuffixPronInfo->NumConversions; i++)
  600. {
  601. /********** Check POS compatability **********/
  602. if (SuffixPronInfo->Conversions[i].FromPos == ActivePos[j])
  603. {
  604. if (!SearchPosSet(SuffixPronInfo->Conversions[i].ToPos, NextActivePos, dwNumNextActivePos))
  605. {
  606. NextActivePos[dwNumNextActivePos] = SuffixPronInfo->Conversions[i].ToPos;
  607. dwNumNextActivePos++;
  608. /********** One time only - concatenate pronunciation, and change POSMatch flag to true **********/
  609. if (dwNumNextActivePos == 1)
  610. {
  611. bPOSMatch = true;
  612. // Append suffix to the rest of the pronunciation...
  613. // Special Cases...
  614. if (pSuffixString[0] == g_phonS[0] && pSuffixString[1] == '\0')
  615. {
  616. hr = Phon_SorZ( pBuffer, wcslen(pBuffer) - 1 );
  617. }
  618. else if (pSuffixString[0] == g_phonD[0] && pSuffixString[1] == '\0')
  619. {
  620. hr = Phon_DorED( pBuffer, wcslen(pBuffer) - 1 );
  621. }
  622. // Default Case...
  623. else
  624. {
  625. if ( SuffixPronInfo == g_SuffixInfoTable + ICISM_SUFFIX ||
  626. SuffixPronInfo == g_SuffixInfoTable + ICIZE_SUFFIX )
  627. {
  628. pBuffer[ wcslen( pBuffer ) - 1 ] = g_phonS[0];
  629. }
  630. // Make sure we don't write past the end of the buffer...
  631. if ( wcslen(pBuffer) + wcslen(pSuffixString) < SP_MAX_PRON_LENGTH )
  632. {
  633. wcscat(pBuffer, pSuffixString);
  634. }
  635. else
  636. {
  637. hr = E_FAIL;
  638. }
  639. }
  640. }
  641. }
  642. }
  643. } // for (short i = 0; i < SuffixPronInfo->NumConversions; i++)
  644. } // for (DWORD j = 0; j < dwNumActivePos; j++)
  645. /********** Update ActivePos values **********/
  646. for (DWORD i = 0; i < dwNumNextActivePos; i++)
  647. {
  648. ActivePos[i] = NextActivePos[i];
  649. }
  650. dwNumActivePos = dwNumNextActivePos;
  651. } // while ( SUCCEEDED(hr) && ListPos && bPOSMatch )
  652. /********** Check to see if any derivations have succeeded **********/
  653. if ( SUCCEEDED(hr) && bPOSMatch )
  654. {
  655. for (DWORD i = 0; i < dwNumActivePos; i++)
  656. {
  657. if (!SearchPosSet(ActivePos[i], FinalPos, dwNumFinalPos))
  658. {
  659. // We have succeeded in deriving a word - add it to the temporary word pron list...
  660. FinalPos[dwNumFinalPos] = ActivePos[i];
  661. dwNumFinalPos++;
  662. if ( bDerivedAWord )
  663. {
  664. // This is not the first successful pronunciation match - need to advance the iterator...
  665. pTempWordPronunciation->pNextWordPronunciation = CreateNextPronunciation( pTempWordPronunciation );
  666. pTempWordPronunciation = pTempWordPronunciation->pNextWordPronunciation;
  667. }
  668. bDerivedAWord = true;
  669. pTempWordPronunciation->eLexiconType = (SPLEXICONTYPE)(pWordPronIterator->eLexiconType | eLEXTYPE_PRIVATE3);
  670. pTempWordPronunciation->ePartOfSpeech = (SPPARTOFSPEECH) ActivePos[i];
  671. pTempWordPronunciation->LangID = pWordPronIterator->LangID;
  672. wcscpy(pTempWordPronunciation->szPronunciation, pBuffer);
  673. pTempWordPronunciation->pNextWordPronunciation = NULL;
  674. }
  675. }
  676. }
  677. // Advance SPWORDPRONUNCIATIONLIST iterator...
  678. if (SUCCEEDED(hr))
  679. {
  680. pWordPronIterator = pWordPronIterator->pNextWordPronunciation;
  681. }
  682. } // while (SUCCEEDED(hr) && pWordPronIterator)
  683. /****************************************
  684. * Did we succeed in deriving anything? *
  685. ****************************************/
  686. /**********************************************************
  687. * If so, copy it into pWordPronunciationList and return. *
  688. **********************************************************/
  689. if ( SUCCEEDED(hr) && bDerivedAWord )
  690. {
  691. // Copy successful words into pWordPronunciationList for eventual return to DoSuffixMorph() caller...
  692. hr = ReallocSPWORDPRONList(pWordPronunciationList, pTempWordPronunciationList->ulSize);
  693. if (SUCCEEDED(hr))
  694. {
  695. pWordPronIterator = pTempWordPronunciationList->pFirstWordPronunciation;
  696. pTempWordPronunciation = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation;
  697. while (SUCCEEDED(hr) && pWordPronIterator)
  698. {
  699. pTempWordPronunciation->eLexiconType = (SPLEXICONTYPE)(pWordPronIterator->eLexiconType);
  700. pTempWordPronunciation->ePartOfSpeech = pWordPronIterator->ePartOfSpeech;
  701. pTempWordPronunciation->LangID = pWordPronIterator->LangID;
  702. wcscpy(pTempWordPronunciation->szPronunciation, pWordPronIterator->szPronunciation);
  703. pWordPronIterator = pWordPronIterator->pNextWordPronunciation;
  704. if (pWordPronIterator)
  705. {
  706. pTempWordPronunciation->pNextWordPronunciation = CreateNextPronunciation( pTempWordPronunciation );
  707. pTempWordPronunciation = pTempWordPronunciation->pNextWordPronunciation;
  708. }
  709. else
  710. {
  711. pTempWordPronunciation->pNextWordPronunciation = NULL;
  712. }
  713. }
  714. }
  715. }
  716. /***************************************
  717. * If not, just do default derivation. *
  718. ***************************************/
  719. else if ( SUCCEEDED(hr) )
  720. {
  721. hr = DefaultAccumulateSuffixes( pSuffixList, pWordPronunciationList );
  722. }
  723. ::CoTaskMemFree(pTempWordPronunciationList->pvBuffer);
  724. delete pTempWordPronunciationList;
  725. return hr;
  726. } /* CSMorph::AccumulateSuffixes */
  727. /*****************************************************************************
  728. * CSMorph::AccumulateSuffixes_LTS *
  729. *---------------------------------*
  730. * Description: Append pronunciations of all the suffixes to the
  731. * retrieved pronunciation of the root word.
  732. *
  733. ********************************************************************** AH ***/
  734. HRESULT CSMorph::AccumulateSuffixes_LTS( CSuffixList *pSuffixList, SPWORDPRONUNCIATIONLIST *pWordPronunciationList )
  735. {
  736. HRESULT hr = S_OK;
  737. SPWORDPRONUNCIATION *pTempWordPronunciation = NULL, *pOriginalWordPronunciation = NULL;
  738. DWORD dwTotalSize = 0, dwNumPos = 0;
  739. SUFFIXPRON_INFO *SuffixPronInfo;
  740. ENGPARTOFSPEECH PartsOfSpeech[NUM_POS] = {MS_Unknown};
  741. WCHAR pBuffer[SP_MAX_PRON_LENGTH];
  742. SPLEXICONTYPE OriginalLexType;
  743. LANGID OriginalLangID;
  744. WORD OriginalReservedField;
  745. /*** Get the original pronunciation ***/
  746. pOriginalWordPronunciation = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation;
  747. OriginalLexType = pOriginalWordPronunciation->eLexiconType;
  748. OriginalLangID = pOriginalWordPronunciation->LangID;
  749. OriginalReservedField = pOriginalWordPronunciation->wReserved;
  750. /*** Get First Suffix ***/
  751. SuffixPronInfo = pSuffixList->RemoveHead();
  752. /*** Copy the pronunciation of the root ***/
  753. wcscpy( pBuffer, pOriginalWordPronunciation->szPronunciation );
  754. /*** Append the pronunciation of the first suffix ***/
  755. if ( SuffixPronInfo->SuffixString[0] == g_phonS[0] &&
  756. SuffixPronInfo->SuffixString[1] == 0 )
  757. {
  758. hr = Phon_SorZ( pBuffer, wcslen(pBuffer) - 1 );
  759. }
  760. else if ( SuffixPronInfo->SuffixString[0] == g_phonD[0] &&
  761. SuffixPronInfo->SuffixString[1] == 0 )
  762. {
  763. hr = Phon_DorED( pBuffer, wcslen(pBuffer) - 1 );
  764. }
  765. else if ( wcslen(pBuffer) + wcslen(SuffixPronInfo->SuffixString) < SP_MAX_PRON_LENGTH )
  766. {
  767. if ( SuffixPronInfo == g_SuffixInfoTable + ICISM_SUFFIX ||
  768. SuffixPronInfo == g_SuffixInfoTable + ICIZE_SUFFIX )
  769. {
  770. pBuffer[ wcslen( pBuffer ) - 1 ] = g_phonS[0];
  771. }
  772. wcscat( pBuffer, SuffixPronInfo->SuffixString );
  773. }
  774. if ( SUCCEEDED( hr ) )
  775. {
  776. /*** Allocate enough space for all of the pronunciations ***/
  777. dwTotalSize = sizeof(SPWORDPRONUNCIATIONLIST) +
  778. ( NUM_POS * ( sizeof(SPWORDPRONUNCIATION) + (SP_MAX_PRON_LENGTH * sizeof(WCHAR) ) ) );
  779. hr = ReallocSPWORDPRONList( pWordPronunciationList, dwTotalSize );
  780. }
  781. if ( SUCCEEDED( hr ) )
  782. {
  783. /*** Build list of parts of speech ***/
  784. for ( int i = 0; i < SuffixPronInfo->NumConversions; i++ )
  785. {
  786. if ( !SearchPosSet( SuffixPronInfo->Conversions[i].ToPos, PartsOfSpeech, dwNumPos ) )
  787. {
  788. PartsOfSpeech[dwNumPos] = SuffixPronInfo->Conversions[i].ToPos;
  789. dwNumPos++;
  790. }
  791. }
  792. pTempWordPronunciation = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation;
  793. /*** Build TempWordPronunciationList to send to AccumulateSuffixes ***/
  794. for ( i = 0; i < (int) dwNumPos; i++ )
  795. {
  796. if ( i > 0 )
  797. {
  798. pTempWordPronunciation->pNextWordPronunciation = CreateNextPronunciation( pTempWordPronunciation );
  799. pTempWordPronunciation = pTempWordPronunciation->pNextWordPronunciation;
  800. }
  801. pTempWordPronunciation->eLexiconType = (SPLEXICONTYPE)(OriginalLexType | eLEXTYPE_PRIVATE3);
  802. pTempWordPronunciation->LangID = OriginalLangID;
  803. pTempWordPronunciation->wReserved = OriginalReservedField;
  804. pTempWordPronunciation->ePartOfSpeech = (SPPARTOFSPEECH)PartsOfSpeech[i];
  805. pTempWordPronunciation->pNextWordPronunciation = NULL;
  806. wcscpy(pTempWordPronunciation->szPronunciation, pBuffer);
  807. }
  808. }
  809. if ( SUCCEEDED( hr ) &&
  810. !pSuffixList->IsEmpty() )
  811. {
  812. /*** Pass accumulated list to AccumulateSuffixes ***/
  813. hr = AccumulateSuffixes( pSuffixList, pWordPronunciationList );
  814. }
  815. return hr;
  816. } /* CSMorph::AccumulateSuffixes_LTS */
  817. /*****************************************************************************
  818. * CSMorph::DefaultAccumulateSuffixes *
  819. *------------------------------------*
  820. * Description: Append pronunciations of all the suffixes to the
  821. * retrieved pronunciation of the root word.
  822. *
  823. * Just accumulate all the pronunciations, and use all of
  824. * the "To" parts of speech of the last suffix. Ex:
  825. *
  826. * cat (Noun) + ing (Verb -> Verb, Verb -> Adj, Verb -> Noun) -> catting (Verb, Adj, Noun)
  827. *
  828. ********************************************************************** AH ***/
  829. HRESULT CSMorph::DefaultAccumulateSuffixes( CSuffixList *pSuffixList, SPWORDPRONUNCIATIONLIST *pWordPronunciationList )
  830. {
  831. HRESULT hr = S_OK;
  832. ENGPARTOFSPEECH PartsOfSpeech[NUM_POS] = { MS_Unknown };
  833. SPWORDPRONUNCIATION *pWordPronIterator = NULL;
  834. WCHAR pBuffer[SP_MAX_PRON_LENGTH];
  835. SUFFIXPRON_INFO *SuffixPronInfo = NULL;
  836. SPLISTPOS ListPos;
  837. DWORD dwTotalSize = 0;
  838. int NumPOS = 0;
  839. SPLEXICONTYPE OriginalLexType;
  840. LANGID OriginalLangID;
  841. WORD OriginalReservedField;
  842. /*** Initialize pBuffer and OriginalXXX variables ***/
  843. ZeroMemory( pBuffer, sizeof( pBuffer ) );
  844. OriginalLexType = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation->eLexiconType;
  845. OriginalLangID = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation->LangID;
  846. OriginalReservedField = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation->wReserved;
  847. /****************************************************************
  848. *** Get Desired Pronunciation of result, and Parts of Speech ***
  849. ****************************************************************/
  850. //--- Get pronunciation of root word
  851. wcscpy( pBuffer, ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation->szPronunciation );
  852. //--- Loop through suffix list, appending pronunciations of suffixes to that of the root.
  853. ListPos = pSuffixList->GetHeadPosition();
  854. //--- List should never be empty at this point
  855. SPDBG_ASSERT( ListPos );
  856. while ( ListPos )
  857. {
  858. SuffixPronInfo = pSuffixList->GetNext( ListPos );
  859. if ( wcslen(pBuffer) + wcslen(SuffixPronInfo->SuffixString) < SP_MAX_PRON_LENGTH )
  860. {
  861. wcscat( pBuffer, SuffixPronInfo->SuffixString );
  862. }
  863. }
  864. //--- Get the "to" parts of speech of the last suffix
  865. for ( int i = 0; i < SuffixPronInfo->NumConversions; i++ )
  866. {
  867. PartsOfSpeech[i] = SuffixPronInfo->Conversions[i].ToPos;
  868. }
  869. NumPOS = i;
  870. /***********************************************************************************
  871. * Now put derived words into pWordPronunciationList for return from DoSuffixMorph *
  872. ***********************************************************************************/
  873. //--- First make sure there is enough room
  874. dwTotalSize = sizeof(SPWORDPRONUNCIATIONLIST) + ( NumPOS * PronSize(pBuffer) );
  875. hr = ReallocSPWORDPRONList( pWordPronunciationList, dwTotalSize );
  876. if ( SUCCEEDED( hr ) )
  877. {
  878. //--- Now add pronunciation once for each part of speech
  879. pWordPronIterator = pWordPronunciationList->pFirstWordPronunciation;
  880. for ( i = 0; i < NumPOS; i++ )
  881. {
  882. pWordPronIterator->eLexiconType = (SPLEXICONTYPE) ( OriginalLexType | eLEXTYPE_PRIVATE3 );
  883. pWordPronIterator->LangID = OriginalLangID;
  884. pWordPronIterator->wReserved = OriginalReservedField;
  885. pWordPronIterator->ePartOfSpeech = (SPPARTOFSPEECH)PartsOfSpeech[i];
  886. wcscpy( pWordPronIterator->szPronunciation, pBuffer );
  887. if ( i < NumPOS - 1 )
  888. {
  889. pWordPronIterator->pNextWordPronunciation = CreateNextPronunciation( pWordPronIterator );
  890. pWordPronIterator = pWordPronIterator->pNextWordPronunciation;
  891. }
  892. else
  893. {
  894. pWordPronIterator->pNextWordPronunciation = NULL;
  895. }
  896. }
  897. }
  898. return hr;
  899. }
  900. /*****************************************************************************
  901. * CSMorph::CheckForMissingE *
  902. *---------------------*
  903. * Description: Check Lexicon to see if the root word has lost an 'e'
  904. * e.g. make -> making
  905. *
  906. ********************************************************************** AH ***/
  907. HRESULT CSMorph::CheckForMissingE( WCHAR *pOrth, long length, DWORD dwFlags,
  908. SPWORDPRONUNCIATIONLIST *pWordPronunciationList)
  909. {
  910. HRESULT hr = S_OK;
  911. WCHAR charSave;
  912. charSave = pOrth[length]; // save orig before we...
  913. pOrth[length] = L'E'; // ...end root with E
  914. hr = LexLookup( pOrth, length+1, dwFlags, pWordPronunciationList );
  915. if ( FAILED(hr) )
  916. {
  917. pOrth[length] = charSave; // restore original char
  918. }
  919. else if ( length > 0 &&
  920. pOrth[length - 1] == L'L' )
  921. {
  922. //--- Check for juggle -> juggler schwa deletion
  923. SPWORDPRONUNCIATION *pWordPronIterator = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation;
  924. while ( pWordPronIterator )
  925. {
  926. if ( wcslen( pWordPronIterator->szPronunciation ) >= 2 )
  927. {
  928. WCHAR *pLastTwoPhonemes = pWordPronIterator->szPronunciation +
  929. ( wcslen( pWordPronIterator->szPronunciation ) - 2 );
  930. if ( wcscmp( pLastTwoPhonemes, g_phonAXl ) == 0 )
  931. {
  932. //--- Orthography ends in -le and pronunciation ends in -AXl, delete AX...
  933. pLastTwoPhonemes[0] = pLastTwoPhonemes[1];
  934. pLastTwoPhonemes[1] = 0;
  935. }
  936. pWordPronIterator = pWordPronIterator->pNextWordPronunciation;
  937. }
  938. }
  939. }
  940. return hr;
  941. } /* CSMorph::CheckForMissingE */
  942. /*****************************************************************************
  943. * CSMorph::CheckForMissingY *
  944. *---------------------------*
  945. * Description: Check Lexicon to see if the root word has lost an 'y'
  946. * e.g. happy -> happily
  947. *
  948. ********************************************************************** AH ***/
  949. HRESULT CSMorph::CheckForMissingY( WCHAR *pOrth, long length, DWORD dwFlags,
  950. SPWORDPRONUNCIATIONLIST *pWordPronunciationList)
  951. {
  952. HRESULT hr = S_OK;
  953. WCHAR charSave;
  954. charSave = pOrth[length]; // save orig before we...
  955. pOrth[length] = L'Y'; // ...end root with E
  956. hr = LexLookup( pOrth, length+1, dwFlags, pWordPronunciationList );
  957. if ( FAILED(hr) )
  958. {
  959. pOrth[length] = charSave; // restore original char
  960. }
  961. else
  962. {
  963. //--- Delete IY at end of pronunciations ( e.g. happy + ily -> [ H AE 1 P (IY) ] + [ AX L IY ] )
  964. for ( SPWORDPRONUNCIATION *pWordPronIterator = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation;
  965. pWordPronIterator; pWordPronIterator = pWordPronIterator->pNextWordPronunciation )
  966. {
  967. if ( pWordPronIterator->szPronunciation[ wcslen( pWordPronIterator->szPronunciation ) - 1 ] == g_phonIY[0] )
  968. {
  969. pWordPronIterator->szPronunciation[ wcslen( pWordPronIterator->szPronunciation ) - 1 ] = 0;
  970. }
  971. }
  972. }
  973. return hr;
  974. } /* CSMorph::CheckForMissingY */
  975. /*****************************************************************************
  976. * CSMorph::CheckForMissingL *
  977. *---------------------------*
  978. * Description: Check Lexicon to see if the root word has lost an 'l'
  979. * e.g. chill -> chilly
  980. *
  981. ********************************************************************** AH ***/
  982. HRESULT CSMorph::CheckForMissingL( WCHAR *pOrth, long length, DWORD dwFlags,
  983. SPWORDPRONUNCIATIONLIST *pWordPronunciationList)
  984. {
  985. HRESULT hr = S_OK;
  986. WCHAR charSave;
  987. charSave = pOrth[length]; // save orig before we...
  988. pOrth[length] = L'L'; // ...end root with E
  989. hr = LexLookup( pOrth, length+1, dwFlags, pWordPronunciationList );
  990. if ( FAILED(hr) )
  991. {
  992. pOrth[length] = charSave; // restore original char
  993. }
  994. else
  995. {
  996. //--- Delete l at end of pronunciations ( e.g. chill +ly -> [ ch ih 1 (l) ] + [ l iy ] )
  997. for ( SPWORDPRONUNCIATION *pWordPronIterator = ((SPWORDPRONUNCIATIONLIST *)pWordPronunciationList)->pFirstWordPronunciation;
  998. pWordPronIterator; pWordPronIterator = pWordPronIterator->pNextWordPronunciation )
  999. {
  1000. if ( pWordPronIterator->szPronunciation[ wcslen( pWordPronIterator->szPronunciation ) - 1 ] == g_phonL[0] )
  1001. {
  1002. pWordPronIterator->szPronunciation[ wcslen( pWordPronIterator->szPronunciation ) - 1 ] = 0;
  1003. }
  1004. }
  1005. }
  1006. return hr;
  1007. } /* CSMorph::CheckForMissingL */
  1008. /*****************************************************************************
  1009. * CSMorph::CheckYtoIMutation *
  1010. *---------------------*
  1011. * Description: Check Lexicon to see if the root word has lost an 'y' to
  1012. * an 'i'
  1013. * e.g. steady + est -> steadiest
  1014. *
  1015. ********************************************************************** AH ***/
  1016. HRESULT CSMorph::CheckYtoIMutation( WCHAR *pOrth, long length, DWORD dwFlags,
  1017. SPWORDPRONUNCIATIONLIST *pWordPronunciationList)
  1018. {
  1019. HRESULT hr = S_OK;
  1020. if ( pOrth[length - 1] == L'I' )
  1021. {
  1022. pOrth[length - 1] = L'Y'; // end root with Y
  1023. hr = LexLookup( pOrth, length, dwFlags, pWordPronunciationList );
  1024. if ( FAILED(hr) )
  1025. {
  1026. pOrth[length - 1] = L'I'; // restore I
  1027. }
  1028. }
  1029. else
  1030. {
  1031. hr = SPERR_NOT_IN_LEX;
  1032. }
  1033. return hr;
  1034. } /* CSMorph::CheckYtoIMutation */
  1035. /*****************************************************************************
  1036. * CSMorph::CheckDoubledMutation *
  1037. *----------------------*
  1038. * Description: Check Lexicon to see if the root word has a doubled
  1039. * consonant.
  1040. * e.g. run + ing -> running
  1041. *
  1042. ********************************************************************** AH ***/
  1043. HRESULT CSMorph::CheckDoubledMutation( WCHAR *pOrth, long length, DWORD dwFlags,
  1044. SPWORDPRONUNCIATIONLIST *pWordPronunciationList)
  1045. {
  1046. HRESULT hr = S_OK;
  1047. switch ( pOrth[length - 1] )
  1048. {
  1049. // Filter the vowels, which never double...
  1050. case L'A':
  1051. case L'E':
  1052. case L'I':
  1053. case L'O':
  1054. case L'U':
  1055. case L'Y':
  1056. // Filter consonants which never double, or are doubled in roots...
  1057. case L'F':
  1058. case L'H':
  1059. case L'K':
  1060. case L'S':
  1061. case L'W':
  1062. case L'Z':
  1063. hr = SPERR_NOT_IN_LEX;
  1064. break;
  1065. default:
  1066. if(pOrth[length-1] == pOrth[length-2]) {
  1067. hr = LexLookup( pOrth, length - 1, dwFlags, pWordPronunciationList );
  1068. break;
  1069. }
  1070. else {
  1071. hr = SPERR_NOT_IN_LEX;
  1072. break;
  1073. }
  1074. }
  1075. return hr;
  1076. } /* CSMorph::CheckDoubledMutation */
  1077. /*****************************************************************************
  1078. * CSMorph::CheckYtoIEMutation *
  1079. *---------------------*
  1080. * Description: Check Lexicon to see if the root word has lost an 'y' to
  1081. * an 'ie'
  1082. * e.g. company + s -> companies
  1083. *
  1084. ********************************************************************** AH ***/
  1085. HRESULT CSMorph::CheckYtoIEMutation( WCHAR *pOrth, long length, DWORD dwFlags,
  1086. SPWORDPRONUNCIATIONLIST *pWordPronunciationList)
  1087. {
  1088. HRESULT hr = S_OK;
  1089. if ( pOrth[length - 1] == L'E' && pOrth[length-2] == L'I' )
  1090. {
  1091. pOrth[length - 2] = L'Y'; // end root with Y
  1092. hr = LexLookup( pOrth, length - 1, dwFlags, pWordPronunciationList );
  1093. if ( FAILED(hr) )
  1094. {
  1095. pOrth[length - 2] = L'I'; // restore I
  1096. }
  1097. }
  1098. else
  1099. {
  1100. hr = SPERR_NOT_IN_LEX;
  1101. }
  1102. return hr;
  1103. } /* CSMorph::CheckYtoIMutation */
  1104. /*****************************************************************************
  1105. * CSMorph::CheckAbleMutation *
  1106. *----------------------------*
  1107. * Description: Check Lexicon for special -able -> -ably cases (e.g.
  1108. * probable -> probably )
  1109. *
  1110. ********************************************************************** AH ***/
  1111. HRESULT CSMorph::CheckAbleMutation( WCHAR *pOrth, long length, DWORD dwFlags,
  1112. SPWORDPRONUNCIATIONLIST *pWordPronunciationList)
  1113. {
  1114. HRESULT hr = S_OK;
  1115. //--- Look up word ending in -able
  1116. pOrth[length+3] = L'E';
  1117. hr = LexLookup( pOrth, length + 4, dwFlags, pWordPronunciationList );
  1118. if ( FAILED( hr ) )
  1119. {
  1120. //--- restore "y"
  1121. pOrth[length+3] = L'Y';
  1122. }
  1123. return hr;
  1124. } /* CSMorph::CheckAbleMutation */
  1125. /*****************************************************************************
  1126. * CSMorph::Phon_SorZ *
  1127. *--------------------*
  1128. * Description: Figure out what phoneme the S suffix should be - s, z, or
  1129. * IXz
  1130. *
  1131. ********************************************************************** AH ***/
  1132. HRESULT CSMorph::Phon_SorZ( WCHAR *pPronunciation, long length )
  1133. {
  1134. HRESULT hr = S_OK;
  1135. if ( SUCCEEDED(hr) && pPronunciation[length] < sp_countof(g_PhonTable) )
  1136. {
  1137. if ( ((PHONTYPE)g_PhonTable[pPronunciation[length]] & ePALATALF) ||
  1138. (pPronunciation[length] == g_phonS[0]) ||
  1139. (pPronunciation[length] == g_phonZ[0]) )
  1140. {
  1141. if ( wcslen(pPronunciation) + wcslen(g_phonAXz) < SP_MAX_PRON_LENGTH )
  1142. {
  1143. wcscat(pPronunciation, g_phonAXz);
  1144. }
  1145. }
  1146. else if( ((PHONTYPE)g_PhonTable[pPronunciation[length]] & eCONSONANTF) &&
  1147. !((PHONTYPE)g_PhonTable[pPronunciation[length]] & eVOICEDF) )
  1148. {
  1149. if ( wcslen(pPronunciation) + wcslen(g_phonZ) < SP_MAX_PRON_LENGTH )
  1150. {
  1151. wcscat(pPronunciation, g_phonS);
  1152. }
  1153. }
  1154. else
  1155. {
  1156. if ( wcslen(pPronunciation) + wcslen(g_phonS) < SP_MAX_PRON_LENGTH )
  1157. {
  1158. wcscat(pPronunciation, g_phonZ);
  1159. }
  1160. }
  1161. }
  1162. else
  1163. {
  1164. hr = E_FAIL;
  1165. }
  1166. return hr;
  1167. } /* CSMorph::Phon_SorZ */
  1168. /*****************************************************************************
  1169. * CSMorph::Phon_DorED *
  1170. *---------------------*
  1171. * Description: Figure out what phoneme the D suffix should be - d, t,
  1172. * or AXd
  1173. *
  1174. ********************************************************************** AH ***/
  1175. HRESULT CSMorph::Phon_DorED( WCHAR *pPronunciation, long length )
  1176. {
  1177. HRESULT hr = S_OK;
  1178. if ( SUCCEEDED(hr) && pPronunciation[length] < sp_countof(g_PhonTable) )
  1179. {
  1180. if ( (pPronunciation[length] == g_phonT[0]) || (pPronunciation[length] == g_phonD[0]) )
  1181. {
  1182. if ( wcslen(pPronunciation) + wcslen(g_phonAXd) < SP_MAX_PRON_LENGTH )
  1183. {
  1184. wcscat(pPronunciation, g_phonAXd);
  1185. }
  1186. }
  1187. else if ((PHONTYPE)g_PhonTable[pPronunciation[length]] & eVOICEDF)
  1188. {
  1189. if ( wcslen(pPronunciation) + wcslen(g_phonD) < SP_MAX_PRON_LENGTH )
  1190. {
  1191. wcscat(pPronunciation, g_phonD);
  1192. }
  1193. }
  1194. else
  1195. {
  1196. if ( wcslen(pPronunciation) + wcslen(g_phonT) < SP_MAX_PRON_LENGTH )
  1197. {
  1198. wcscat(pPronunciation, g_phonT);
  1199. }
  1200. }
  1201. }
  1202. else
  1203. {
  1204. hr = E_FAIL;
  1205. }
  1206. return hr;
  1207. } /* CSMorph::Phon_DorED */
  1208. //--- End of File -------------------------------------------------------------