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.
557 lines
18 KiB
557 lines
18 KiB
/////////////////////////////////////////////////////////
|
|
// TestITN_CHS.cpp : Implementation of CTestITN_CHS
|
|
//
|
|
// ITN Interpretor for Simplified Chinese:
|
|
//
|
|
// Integer,
|
|
// Decimal,
|
|
// Percent,
|
|
// Ratio,
|
|
// Fraction,
|
|
// Minus number,
|
|
// Time
|
|
//
|
|
/////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "Itngram_CHS.h"
|
|
#include "TestITN_CHS.h"
|
|
#include "sphelper.h"
|
|
#include "test_CHS.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTestITN_CHS
|
|
/****************************************************************************
|
|
* CTestITN_CHS::InitGrammar *
|
|
*-------------------------*
|
|
* Description:
|
|
*
|
|
* Returns:
|
|
*
|
|
********************************************************************* RAL ***/
|
|
|
|
STDMETHODIMP CTestITN_CHS::InitGrammar(const WCHAR * pszGrammarName, const void ** pvGrammarData)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRSRC hResInfo = ::FindResource(_Module.GetModuleInstance(), _T("TEST"), _T("ITNGRAMMAR"));
|
|
if (hResInfo)
|
|
{
|
|
HGLOBAL hData = ::LoadResource(_Module.GetModuleInstance(), hResInfo);
|
|
if (hData)
|
|
{
|
|
*pvGrammarData = ::LockResource(hData);
|
|
if (*pvGrammarData == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* CTestITN_CHS::Interpret *
|
|
*-----------------------*
|
|
* Description:
|
|
*
|
|
* Returns:
|
|
*
|
|
********************************************************************* RAL ***/
|
|
|
|
class CSpPhrasePtrTemp : public CSpPhrasePtr
|
|
{
|
|
public:
|
|
|
|
const WCHAR * TextValueOfId(ULONG IdProp);
|
|
const double DoubleValueOfId(ULONG IdProp);
|
|
const ULONGLONG ULongLongValueOfId(ULONG IdProp);
|
|
HRESULT ElementInfoOfId(ULONG IdProp, ULONG *pulFirstElement, ULONG *pulCountOfElements);
|
|
|
|
private:
|
|
|
|
const SPPHRASEPROPERTY * FindPropertyById(ULONG IdProp);
|
|
const SPPHRASEPROPERTY * FindPropertyByIdHelper(ULONG IdProp, const SPPHRASEPROPERTY *);
|
|
};
|
|
|
|
const WCHAR * CSpPhrasePtrTemp::TextValueOfId(ULONG IdProp)
|
|
{
|
|
_ASSERT(m_pPhrase);
|
|
SPDBG_ASSERT(m_pPhrase);
|
|
|
|
const SPPHRASEPROPERTY * pProp = FindPropertyById(IdProp);
|
|
|
|
return pProp ? pProp->pszValue : NULL;
|
|
}
|
|
|
|
const double CSpPhrasePtrTemp::DoubleValueOfId(ULONG IdProp)
|
|
{
|
|
SPDBG_ASSERT(m_pPhrase);
|
|
|
|
const SPPHRASEPROPERTY * pProp = FindPropertyById(IdProp);
|
|
|
|
return pProp ? pProp->vValue.dblVal : 0;
|
|
}
|
|
|
|
const ULONGLONG CSpPhrasePtrTemp::ULongLongValueOfId(ULONG IdProp)
|
|
{
|
|
SPDBG_ASSERT(m_pPhrase);
|
|
|
|
const SPPHRASEPROPERTY * pProp = FindPropertyById(IdProp);
|
|
|
|
return pProp ? pProp->vValue.ulVal : 0;
|
|
}
|
|
|
|
HRESULT CSpPhrasePtrTemp::ElementInfoOfId(ULONG IdProp, ULONG *pulFirstElement, ULONG *pulCountOfElements)
|
|
{
|
|
_ASSERT(m_pPhrase);
|
|
SPDBG_ASSERT(m_pPhrase);
|
|
|
|
const SPPHRASEPROPERTY * pProp = FindPropertyById(IdProp);
|
|
|
|
if (pProp)
|
|
{
|
|
*pulFirstElement = pProp->ulFirstElement;
|
|
*pulCountOfElements = pProp->ulCountOfElements;
|
|
}
|
|
else
|
|
{
|
|
*pulFirstElement = *pulCountOfElements = 0;
|
|
}
|
|
|
|
return pProp ? S_OK : E_FAIL;
|
|
}
|
|
|
|
const SPPHRASEPROPERTY * CSpPhrasePtrTemp::FindPropertyById(const ULONG IdProp)
|
|
{
|
|
return FindPropertyByIdHelper(IdProp, m_pPhrase->pProperties);
|
|
}
|
|
|
|
const SPPHRASEPROPERTY * CSpPhrasePtrTemp::FindPropertyByIdHelper(ULONG IdProp, const SPPHRASEPROPERTY * pProp)
|
|
{
|
|
const SPPHRASEPROPERTY * pRet = NULL;
|
|
|
|
if (pProp->ulId == IdProp)
|
|
{
|
|
pRet = pProp;
|
|
}
|
|
else
|
|
{
|
|
if (pProp->pFirstChild)
|
|
{
|
|
pRet = FindPropertyByIdHelper(IdProp, pProp->pFirstChild);
|
|
}
|
|
|
|
if (!pRet && pProp->pNextSibling)
|
|
{
|
|
pRet = FindPropertyByIdHelper(IdProp, pProp->pNextSibling);
|
|
}
|
|
}
|
|
|
|
return pRet;
|
|
}
|
|
|
|
// assume that we have only THOUSANDS(qian), HUNDREDS(bai), TENS(shi), and ONES(ge) here!!
|
|
HRESULT ComputeNum9999(const SPPHRASEPROPERTY *pProperties, __int64 *pVal, ULONG *pulLength)
|
|
{
|
|
ULONG ulVal = 0;
|
|
|
|
if (pProperties->pFirstChild)
|
|
{
|
|
for (const SPPHRASEPROPERTY * pProp = pProperties; pProp; pProp = pProp->pNextSibling)
|
|
{
|
|
if ( 0 != pProp->ulId )
|
|
{
|
|
SPDBG_ASSERT( pProp->pFirstChild );
|
|
SPDBG_ASSERT( VT_UI4 == pProp->vValue.vt );
|
|
SPDBG_ASSERT( VT_UI4 == pProp->pFirstChild->vValue.vt );
|
|
|
|
ulVal += pProp->pFirstChild->vValue.ulVal * pProp->vValue.ulVal;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pVal = ulVal;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT ComputeNum10000(const SPPHRASEPROPERTY *pProperties, __int64 *pVal, ULONG *pulLength)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
*pVal = 0;
|
|
*pulLength = 0;
|
|
|
|
WCHAR * pszStopped;
|
|
ULONG v2 = wcstol(pProperties->pszValue, &pszStopped, 10);
|
|
*pVal += v2;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* GetMinAndMaxPos *
|
|
*-----------------*
|
|
* Description:
|
|
* Gets the minimum and maximum elements spanned by the
|
|
* set of properties
|
|
*************************************************************************/
|
|
void GetMinAndMaxPos( const SPPHRASEPROPERTY *pProperties,
|
|
ULONG *pulMinPos,
|
|
ULONG *pulMaxPos )
|
|
{
|
|
if ( !pulMinPos || !pulMaxPos )
|
|
{
|
|
return;
|
|
}
|
|
ULONG ulMin = 9999999;
|
|
ULONG ulMax = 0;
|
|
|
|
for ( const SPPHRASEPROPERTY *pProp = pProperties; pProp; pProp = pProp->pNextSibling )
|
|
{
|
|
ulMin = __min( ulMin, pProp->ulFirstElement );
|
|
ulMax = __max( ulMax, pProp->ulFirstElement + pProp->ulCountOfElements );
|
|
}
|
|
*pulMinPos = ulMin;
|
|
*pulMaxPos = ulMax;
|
|
} /* GetMinAndMaxPos */
|
|
|
|
HRESULT FormatOutput(WCHAR *pBuffer, __int64 Value)
|
|
{
|
|
swprintf(pBuffer, L"%I64d", Value);
|
|
if (Value < 0)
|
|
pBuffer++; // keep the '-', replace the rest
|
|
|
|
int l = wcslen(pBuffer);
|
|
if (l<=3)
|
|
return S_OK;
|
|
|
|
int head = l%3;
|
|
int block = l/3;
|
|
|
|
WCHAR buf[100];
|
|
wcscpy(buf, pBuffer);
|
|
pBuffer[0] = 0;
|
|
|
|
if (head)
|
|
{
|
|
wcsncat(pBuffer, buf, head);
|
|
pBuffer[head] = 0;
|
|
wcscat(pBuffer, L",");
|
|
}
|
|
|
|
for (int i=0; i<block; i++)
|
|
{
|
|
wcsncat(pBuffer, buf+i*3+head, 3);
|
|
if (i<block-1)
|
|
wcscat(pBuffer, L",");
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTestITN_CHS::Interpret(ISpPhraseBuilder * pPhrase, const ULONG ulFirstElement, const ULONG ulCountOfElements, ISpCFGInterpreterSite * pSite)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulRuleId = 0;
|
|
CSpPhrasePtrTemp cpPhrase;
|
|
WCHAR szBuff[MAX_PATH], szBuff2[MAX_PATH]; /* pwch;*/
|
|
szBuff[0] = 0;
|
|
szBuff2[0] = 0;
|
|
|
|
hr = pPhrase->GetPhrase(&cpPhrase);
|
|
m_pSite = pSite;
|
|
|
|
ULONG ulMinPos;
|
|
ULONG ulMaxPos;
|
|
GetMinAndMaxPos( cpPhrase->pProperties, &ulMinPos, &ulMaxPos );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
switch (cpPhrase->Rule.ulId)
|
|
{
|
|
case GRID_NUMBER: // Number
|
|
{
|
|
__int64 ulValue = 0;
|
|
ULONG ulLength = 0;
|
|
//ULONG ulMinPos = 999999999;
|
|
//ULONG ulMaxPos = 0;
|
|
for (const SPPHRASEPROPERTY * pProp = cpPhrase->pProperties; pProp; pProp ? pProp = pProp->pNextSibling : NULL)
|
|
{
|
|
switch(pProp->ulId)
|
|
{
|
|
case TENTHOUSANDS_:
|
|
{
|
|
__int64 v1 = 0;
|
|
_ASSERT(pProp);
|
|
SPDBG_ASSERT(pProp);
|
|
hr = ComputeNum10000(pProp, &v1, &ulLength);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ulValue += v1 * 10000;
|
|
}
|
|
}
|
|
break;
|
|
case TENTHOUSANDS:
|
|
{
|
|
__int64 v1 = 0;
|
|
_ASSERT(pProp->pFirstChild);
|
|
SPDBG_ASSERT(pProp->pFirstChild);
|
|
hr = ComputeNum9999(pProp->pFirstChild, &v1, &ulLength);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ulValue += v1 * 10000;
|
|
}
|
|
}
|
|
break;
|
|
case HUNDREDMILLIONS:
|
|
{
|
|
__int64 v1 = 0;
|
|
_ASSERT(pProp->pFirstChild);
|
|
SPDBG_ASSERT(pProp->pFirstChild);
|
|
hr = ComputeNum9999(pProp->pFirstChild, &v1, &ulLength);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ulValue += v1 * 100000000;
|
|
}
|
|
}
|
|
break;
|
|
case ONES:
|
|
{
|
|
__int64 v1 = 0;
|
|
SPDBG_ASSERT(pProp->pFirstChild);
|
|
hr = ComputeNum9999(pProp->pFirstChild, &v1, &ulLength);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ulValue += v1;
|
|
pProp = NULL;
|
|
}
|
|
}
|
|
break;
|
|
case ONES_THOUSANDS:
|
|
{
|
|
SPDBG_ASSERT(pProp->pFirstChild);
|
|
ulValue += pProp->pFirstChild->vValue.ulVal;
|
|
pProp = NULL;
|
|
}
|
|
break;
|
|
case THOUSANDS:
|
|
case HUNDREDS:
|
|
default:
|
|
_ASSERT(false);
|
|
SPDBG_ASSERT(false);
|
|
}
|
|
}
|
|
|
|
ATLTRACE(L"GRID_NUMBER: %d\t(%d + %d)\n", ulValue, ulMinPos, ulMaxPos - ulMinPos);
|
|
FormatOutput(szBuff, ulValue);
|
|
}
|
|
break;
|
|
|
|
case GRID_DECIMAL:
|
|
{
|
|
szBuff2[0] = 0;
|
|
for (const SPPHRASEPROPERTY * pProp = cpPhrase->pProperties; pProp; pProp = pProp->pNextSibling)
|
|
{
|
|
switch (pProp->ulId)
|
|
{
|
|
case INTEGER:
|
|
{
|
|
wcscpy(szBuff, pProp->pszValue);
|
|
wcscat(szBuff, L".");
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
wcscat(szBuff2, pProp->pszValue);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
ATLTRACE(L"GRID_DECIMAL");
|
|
wcscat(szBuff, szBuff2);
|
|
}
|
|
break;
|
|
|
|
case PERCENT:
|
|
{
|
|
for (const SPPHRASEPROPERTY * pProp = cpPhrase->pProperties; pProp; pProp = pProp->pNextSibling)
|
|
{
|
|
switch (pProp->ulId)
|
|
{
|
|
case DECIMAL:
|
|
case INTEGER:
|
|
{
|
|
wcscpy(szBuff, pProp->pszValue);
|
|
wcscat(szBuff, L"%");
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
ATLTRACE(L"PERCENT");
|
|
}
|
|
break;
|
|
|
|
case PERCENT100:
|
|
{
|
|
ATLTRACE(L"PERCENT100");
|
|
wcscpy(szBuff, L"100%");
|
|
}
|
|
break;
|
|
|
|
case RATIO:
|
|
{
|
|
for (const SPPHRASEPROPERTY * pProp = cpPhrase->pProperties; pProp; pProp = pProp->pNextSibling)
|
|
{
|
|
switch (pProp->ulId)
|
|
{
|
|
case RATIO1:
|
|
wcscpy(szBuff, pProp->pszValue);
|
|
break;
|
|
case RATIO2:
|
|
wcscpy(szBuff2, pProp->pszValue);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
ATLTRACE(L"RATIO");
|
|
wcscat(szBuff, L":");
|
|
wcscat(szBuff, szBuff2);
|
|
}
|
|
break;
|
|
|
|
case FRACTION:
|
|
{
|
|
for (const SPPHRASEPROPERTY * pProp = cpPhrase->pProperties; pProp; pProp = pProp->pNextSibling)
|
|
{
|
|
switch (pProp->ulId)
|
|
{
|
|
case DENOMINATOR:
|
|
wcscpy(szBuff2, pProp->pszValue);
|
|
break;
|
|
case NUMERATOR:
|
|
wcscpy(szBuff, pProp->pszValue);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
ATLTRACE(L"FRACTION");
|
|
wcscat(szBuff, L"/");
|
|
wcscat(szBuff, szBuff2);
|
|
}
|
|
break;
|
|
|
|
case GRID_NUMBER_MINUS:
|
|
{
|
|
for (const SPPHRASEPROPERTY * pProp = cpPhrase->pProperties; pProp; pProp = pProp->pNextSibling)
|
|
{
|
|
switch (pProp->ulId)
|
|
{
|
|
case POS_OF_MINUS:
|
|
wcscpy(szBuff2, pProp->pszValue);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
ATLTRACE(L"GRID_NUMBER_MINUS");
|
|
wcscpy(szBuff, L"-");
|
|
wcscat(szBuff, szBuff2);
|
|
}
|
|
break;
|
|
|
|
case TIME:
|
|
{
|
|
for (const SPPHRASEPROPERTY * pProp = cpPhrase->pProperties; pProp; pProp = pProp->pNextSibling)
|
|
{
|
|
switch (pProp->ulId)
|
|
{
|
|
case HOUR:
|
|
wcscpy(szBuff, pProp->pszValue);
|
|
break;
|
|
case MINUTE:
|
|
wcscpy(szBuff2, pProp->pszValue);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
ATLTRACE(L"TIME");
|
|
wcscat(szBuff, L":");
|
|
wcscat(szBuff, szBuff2);
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
_ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
hr = AddPropertyAndReplacement( szBuff, 0,
|
|
ulMinPos, ulMaxPos, ulMinPos, ulMaxPos - ulMinPos );//ulFirstElement, ulCountOfElements );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* CTestITN_CHS::AddPropertyAndReplacement *
|
|
*---------------------------------------*
|
|
* Description:
|
|
* Takes all of the info that we want to pass into the
|
|
* engine site, forms the SPPHRASEPROPERTY and
|
|
* SPPHRASERREPLACEMENT, and adds them to the engine site
|
|
* Return:
|
|
* Return values of ISpCFGInterpreterSite::AddProperty()
|
|
* and ISpCFGInterpreterSite::AddTextReplacement()
|
|
*************************************************************************/
|
|
HRESULT CTestITN_CHS::AddPropertyAndReplacement( const WCHAR *szBuff,
|
|
const DOUBLE dblValue,
|
|
const ULONG ulMinPos,
|
|
const ULONG ulMaxPos,
|
|
const ULONG ulFirstElement,
|
|
const ULONG ulCountOfElements )
|
|
{
|
|
// Add the property
|
|
SPPHRASEPROPERTY prop;
|
|
memset(&prop,0,sizeof(prop));
|
|
prop.pszValue = szBuff;
|
|
prop.vValue.vt = VT_R8;
|
|
prop.vValue.dblVal = dblValue;
|
|
prop.ulFirstElement = ulMinPos;
|
|
prop.ulCountOfElements = ulMaxPos - ulMinPos;
|
|
HRESULT hr = m_pSite->AddProperty(&prop);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SPPHRASEREPLACEMENT repl;
|
|
memset(&repl,0, sizeof(repl));
|
|
//repl.bDisplayAttributes = SPAF_ONE_TRAILING_SPACE;
|
|
// No space after the ITNed string in Chinese
|
|
repl.bDisplayAttributes = 0;
|
|
repl.pszReplacementText = szBuff;
|
|
repl.ulFirstElement = ulFirstElement;
|
|
repl.ulCountOfElements = ulCountOfElements;
|
|
hr = m_pSite->AddTextReplacement(&repl);
|
|
}
|
|
|
|
return hr;
|
|
} /* CTestITN_CHS::AddPropertyAndReplacement */
|