|
|
%{
class CValueParser;
#if 0
%}
%union { WCHAR * pwszChar; DBCOMMANDOP dbop; CDbRestriction * pRest; CStorageVariant * pStorageVar; CValueParser *pPropValueParser; int iInt; int iEmpty; }
%left _OR %left _AND _NEAR _NEARDIST %left _NOT %left '(' ')'
/*** *** Tokens (used also by flex via parser.h) ***/
/*** *** reserved_words ***/
%token _CONTAINS %token _AND %token _OR %token _NOT %token _NEAR %token _LT %token _GT %token _LTE %token _GTE %token _EQ %token _NE %token _ALLOF %token _SOMEOF %token _OPEN %token _CLOSE %token _VECTOR_END %token _VE %token _VE_END %token _PROPEND %token _NEAR_END
%token _LTSOME %token _GTSOME %token _LTESOME %token _GTESOME %token _EQSOME %token _NESOME %token _ALLOFSOME %token _SOMEOFSOME
%token _LTALL %token _GTALL %token _LTEALL %token _GTEALL %token _EQALL %token _NEALL %token _ALLOFALL %token _SOMEOFALL %token _COERCE
%token _SHGENPREFIX %token _SHGENINFLECT %token _GENPREFIX %token _GENINFLECT %token _GENNORMAL
/*** *** Terminal tokens ***/ %token <pwszChar> _PHRASE %token <pwszChar> _PROPNAME %token <pwszChar> _NEARDIST %token <pwszChar> _NEARUNIT %token <pwszChar> _WEIGHT %token <pwszChar> _REGEX %token <pwszChar> _FREETEXT %token <pwszChar> _VECTORELEMENT %token <pwszChar> _VEMETHOD %token <pwszChar> _PHRASEORREGEX
/*** *** Nonterminal tokens ***/
%type <pStorageVar> Value %type <pStorageVar> VectorValue %type <pPropValueParser> SingletVector %type <pPropValueParser> EmptyVector %type <pPropValueParser> MultiVector %type <dbop> Op %type <dbop> Matches %type <iEmpty> Property // placeholder. value is empty (info saved to state) %type <iEmpty> Contains // placeholder. value is empty %type <iEmpty> Open // placeholder. value is empty %type <iEmpty> Close // placeholder. value is empty %type <iInt> Gen %type <iEmpty> GenEnd // placeholder. value is empty (info saved to state) %type <iEmpty> PropEnd // placeholder. value is empty (info saved to state) %type <iInt> ShortGen
%type <pRest> Term %type <pRest> PropTerm %type <pRest> NestTerm %type <pRest> CoerceTerm %type <pRest> NearTerm %type <pRest> AndTerm %type <pRest> VectorTerm %type <pRest> VectorSpec %type <pRest> query
%{
#endif
#define YYDEBUG CIDBG
#include <malloc.h> #include "yybase.hxx" #include "parser.h" // defines yystype #include "parsepl.h" #include "flexcpp.h"
#if CIDBG == 1 #define AssertReq(x) Assert(x != NULL) #else #define AssertReq(x) #endif
const GUID guidSystem = PSGUID_STORAGE; static CDbColId psContents( guidSystem, PID_STG_CONTENTS );
//+--------------------------------------------------------------------------- // // Function: TreeFromText, public // // Synopsis: Create a CDbRestriction from a restriction string // // Arguments: [wcsRestriction] -- restriction // [ColumnMapper] -- property list // [lcid] -- locale id of the query // // History: 01-Oct-97 emilyb created // 26-Aug-98 KLam No longer need to lower case // //----------------------------------------------------------------------------
CDbContentRestriction * TreeFromText( WCHAR const * wcsRestriction, IColumnMapper & ColumnMapper, LCID lcid ) { unsigned cwc = 1 + wcslen( wcsRestriction ); XGrowable<WCHAR> xRestriction( cwc ); WCHAR * pwc = xRestriction.Get(); RtlCopyMemory( pwc, wcsRestriction, cwc * sizeof WCHAR );
cwc--;
// The parser can't deal with trailing space so strip it off
while ( cwc > 0 && L' ' == pwc[cwc-1] ) cwc--; pwc[cwc] = 0;
TripLexer Lexer; XPtr<YYPARSER> xParser( new TripParser( ColumnMapper, lcid, Lexer ) );
xParser->yyprimebuffer( pwc );
#if 0 // YYDEBUG == 1 // Set this to 1 if you want command line output. to 0 otherwise. xParser->SetDebug(); #endif
// Actually parse the text producing a tree
SCODE hr = xParser->Parse();
if (FAILED(hr)) THROW( CException( hr ) );
// return the DBCOMMANDTREE return (CDbContentRestriction *)( xParser->GetParseTree() );
} //TextFromTree
void StripQuotes(WCHAR *wcsPhrase) { ULONG cChars = wcslen(wcsPhrase); LPWSTR pLast = wcsPhrase + cChars - 1; if (L'"' == *wcsPhrase && L'"' == *pLast) { *pLast = L'\0'; MoveMemory(wcsPhrase, wcsPhrase+1, sizeof(WCHAR) * (cChars-1) ); } }
//+--------------------------------------------------------------------------- // // Member: CValueParser::CValueParser, public // // Synopsis: Allocs CStorageVariant of correct type // // History: 01-Oct-97 emilyb created // 02-Sep-98 KLam Added locale // //----------------------------------------------------------------------------
CValueParser::CValueParser( BOOL fVectorElement, DBTYPE PropType, LCID locale ) : _pStgVariant( 0 ), _fVector(fVectorElement), _PropType (PropType), _cElements ( 0 ), _locale ( locale ) {
if ( _fVector ) { // this is a vector if ( DBTYPE_VECTOR != ( _PropType & DBTYPE_VECTOR ) ) THROW( CParserException( QPARSE_E_EXPECTING_PHRASE ) );
VARENUM ve = (VARENUM ) _PropType; if ( _PropType == ( DBTYPE_VECTOR | DBTYPE_WSTR ) ) ve = (VARENUM) (VT_VECTOR | VT_LPWSTR); else if ( _PropType == ( DBTYPE_VECTOR | DBTYPE_STR ) ) ve = (VARENUM) (VT_VECTOR | VT_LPSTR);
_pStgVariant.Set( new CStorageVariant( ve, _cElements ) ); } else { _pStgVariant.Set( new CStorageVariant() ); } if ( _pStgVariant.IsNull() ) THROW( CException( E_OUTOFMEMORY ) ); }
//+--------------------------------------------------------------------------- // // Member: CValueParser::AddValue, public // // Synopsis: Adds value to CStorageVariant // // Arguments: [pwszValue] -- value // // History: 01-Oct-97 emilyb code moved here from CPropertyValueParser // //----------------------------------------------------------------------------
void CValueParser::AddValue(WCHAR const * pwszValue) { if ( _pStgVariant.IsNull() ) THROW( CException( E_OUTOFMEMORY ) );
switch ( _PropType & ~DBTYPE_VECTOR ) {
case DBTYPE_WSTR : case DBTYPE_WSTR | DBTYPE_BYREF : { if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetLPWSTR( pwszValue, _cElements ); else _pStgVariant->SetLPWSTR( pwszValue ); break; } case DBTYPE_BSTR : { BSTR bstr = SysAllocString( pwszValue );
if ( 0 == bstr ) THROW( CException( E_OUTOFMEMORY ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetBSTR( bstr, _cElements ); else _pStgVariant->SetBSTR( bstr );
SysFreeString( bstr ); break; } case DBTYPE_STR : case DBTYPE_STR | DBTYPE_BYREF : { // make sure there's enough room to translate
unsigned cbBuffer = 1 + 3 * wcslen( pwszValue ); XArray<char> xBuf( cbBuffer );
int cc = WideCharToMultiByte( CP_ACP, 0, pwszValue, -1, xBuf.Get(), cbBuffer, NULL, NULL );
if ( 0 == cc ) { #if CIDBG ULONG ul = GetLastError(); #endif THROW( CParserException( QPARSE_E_EXPECTING_PHRASE ) ); }
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetLPSTR( xBuf.Get(), _cElements ); else _pStgVariant->SetLPSTR( xBuf.Get() ); break; }
case DBTYPE_I1 : { CQueryScanner scan( pwszValue, FALSE, _locale ); LONG l = 0; BOOL fAtEndOfString; if ( ! ( scan.GetNumber( l, fAtEndOfString ) && fAtEndOfString ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( ( l > SCHAR_MAX ) || ( l < SCHAR_MIN ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetI1( (CHAR) l, _cElements ); else _pStgVariant->SetI1( (CHAR) l );
break; } case DBTYPE_UI1 : { CQueryScanner scan( pwszValue, FALSE, _locale ); ULONG ul = 0; BOOL fAtEndOfString; if ( ! ( scan.GetNumber( ul, fAtEndOfString ) && fAtEndOfString ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( ul > UCHAR_MAX ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetUI1( (BYTE) ul, _cElements ); else _pStgVariant->SetUI1( (BYTE) ul );
break; } case DBTYPE_I2 : { CQueryScanner scan( pwszValue, FALSE, _locale ); LONG l = 0; BOOL fAtEndOfString; if ( ! ( scan.GetNumber( l, fAtEndOfString ) && fAtEndOfString ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( ( l > SHRT_MAX ) || ( l < SHRT_MIN ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetI2( (short) l, _cElements ); else _pStgVariant->SetI2( (short) l );
break; } case DBTYPE_UI2 : { CQueryScanner scan( pwszValue, FALSE, _locale ); ULONG ul = 0; BOOL fAtEndOfString; if ( ! ( scan.GetNumber( ul, fAtEndOfString ) && fAtEndOfString ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( ul > USHRT_MAX ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetUI2( (USHORT) ul, _cElements ); else _pStgVariant->SetUI2( (USHORT) ul ); break; } case DBTYPE_I4 : { CQueryScanner scan( pwszValue, FALSE, _locale ); LONG l = 0; BOOL fAtEndOfString; if ( ! ( scan.GetNumber( l, fAtEndOfString ) && fAtEndOfString ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetI4( l, _cElements ); else _pStgVariant->SetI4( l ); break; } case DBTYPE_UI4 : { CQueryScanner scan( pwszValue, FALSE, _locale ); ULONG ul = 0; BOOL fAtEndOfString; if ( ! ( scan.GetNumber( ul, fAtEndOfString ) && fAtEndOfString ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetUI4( ul, _cElements ); else _pStgVariant->SetUI4( ul ); break; } case DBTYPE_ERROR : { // SCODE/HRESULT are typedefed as long (signed)
CQueryScanner scan( pwszValue, FALSE, _locale ); SCODE sc = 0; BOOL fAtEndOfString; if ( ! ( scan.GetNumber( sc, fAtEndOfString ) && fAtEndOfString ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetERROR( sc, _cElements ); else _pStgVariant->SetERROR( sc ); break; } case DBTYPE_I8 : { CQueryScanner scan( pwszValue, FALSE, _locale ); _int64 ll = 0; BOOL fAtEndOfString; if ( ! ( scan.GetNumber( ll, fAtEndOfString ) && fAtEndOfString ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
LARGE_INTEGER LargeInt; LargeInt.QuadPart = ll;
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetI8( LargeInt , _cElements ); else _pStgVariant->SetI8( LargeInt );
break; } case DBTYPE_UI8 : { CQueryScanner scan( pwszValue, FALSE, _locale ); unsigned _int64 ull = 0; BOOL fAtEndOfString; if ( ! ( scan.GetNumber( ull, fAtEndOfString ) && fAtEndOfString ) ) THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
ULARGE_INTEGER LargeInt; LargeInt.QuadPart = ull;
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetUI8( LargeInt , _cElements ); else _pStgVariant->SetUI8( LargeInt );
break; } case DBTYPE_BOOL : { if ( pwszValue[0] == 'T' || pwszValue[0] == 't' ) if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetBOOL( VARIANT_TRUE, _cElements ); else _pStgVariant->SetBOOL( VARIANT_TRUE ); else if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetBOOL( VARIANT_FALSE, _cElements ); else _pStgVariant->SetBOOL( VARIANT_FALSE );
break; } case DBTYPE_R4 : { WCHAR *pwcEnd = 0;
float Float = (float)( wcstod( pwszValue, &pwcEnd ) );
if ( *pwcEnd != 0 && !iswspace( *pwcEnd ) ) THROW( CParserException( QPARSE_E_EXPECTING_REAL ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetR4( Float, _cElements ); else _pStgVariant->SetR4( Float );
break; } case DBTYPE_R8 : { WCHAR *pwcEnd = 0; double Double = ( double )( wcstod( pwszValue, &pwcEnd ) );
if ( *pwcEnd != 0 && !iswspace( *pwcEnd ) ) THROW( CParserException( QPARSE_E_EXPECTING_REAL ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetR8( Double, _cElements ); else _pStgVariant->SetR8( Double );
break; } case DBTYPE_DECIMAL : { WCHAR *pwcEnd = 0; double Double = ( double )( wcstod( pwszValue, &pwcEnd ) ); if( *pwcEnd != 0 && !iswspace( *pwcEnd ) ) THROW( CParserException( QPARSE_E_EXPECTING_REAL ) ); // Vectors are not supported by OLE for VT_DECIMAL (yet) Win4Assert( 0 == ( _PropType & DBTYPE_VECTOR ) ); PROPVARIANT * pPropVar = (PROPVARIANT *) _pStgVariant.GetPointer(); VarDecFromR8( Double, &(pPropVar->decVal) ); pPropVar->vt = VT_DECIMAL; break; } case DBTYPE_DATE : { FILETIME ftValue; ParseDateTime( pwszValue, ftValue );
SYSTEMTIME stValue; BOOL fOK = FileTimeToSystemTime( &ftValue, &stValue );
if ( !fOK ) THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
DATE dosDate; fOK = SystemTimeToVariantTime( &stValue, &dosDate );
if ( !fOK ) THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetDATE( dosDate, _cElements ); else _pStgVariant->SetDATE( dosDate );
break; } case VT_FILETIME : { FILETIME ftValue; ParseDateTime( pwszValue, ftValue );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetFILETIME( ftValue, _cElements ); else _pStgVariant->SetFILETIME( ftValue );
break; } case DBTYPE_CY : { double dbl;
if ( swscanf( pwszValue, L"%lf", &dbl ) < 1 ) THROW( CParserException( QPARSE_E_EXPECTING_CURRENCY ) );
CY cyCurrency; VarCyFromR8( dbl, &cyCurrency );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetCY( cyCurrency, _cElements ); else _pStgVariant->SetCY( cyCurrency );
break; } case DBTYPE_GUID : case DBTYPE_GUID | DBTYPE_BYREF: { CLSID clsid;
if ( swscanf( pwszValue, L"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", &clsid.Data1, &clsid.Data2, &clsid.Data3, &clsid.Data4[0], &clsid.Data4[1], &clsid.Data4[2], &clsid.Data4[3], &clsid.Data4[4], &clsid.Data4[5], &clsid.Data4[6], &clsid.Data4[7] ) < 11 ) THROW( CParserException( QPARSE_E_EXPECTING_GUID ) );
if ( _PropType & DBTYPE_VECTOR ) _pStgVariant->SetCLSID( clsid, _cElements ); else _pStgVariant->SetCLSID( &clsid ); break; } default: { THROW( CParserException( QPARSE_E_UNSUPPORTED_PROPERTY_TYPE ) ); } } // switch
// make sure memory allocations succeeded
if ( !_pStgVariant->IsValid() ) THROW( CException( E_OUTOFMEMORY ) );
if ( _fVector ) { _cElements++; } }
//+--------------------------------------------------------------------------- // // Member: CValueParser::ParseDateTime, private // // Synopsis: Attempts to parse a date expression. // // Arguments: phrase -- pointer to the phrase to parse // ft -- reference to the FILETIME structure to fill in // with the result // // History: 31-May-96 dlee Created // 23-Jan-97 KyleP Better Year 2000 support // 02-Sep-98 KLam Use user settings for Y2K support // //----------------------------------------------------------------------------
void CValueParser::ParseDateTime( WCHAR const * phrase, FILETIME & ft ) { if( !CheckForRelativeDate( phrase, ft ) ) { SYSTEMTIME stValue = { 0, 0, 0, 0, 0, 0, 0, 0 };
int cItems = swscanf( phrase, L"%4hd/%2hd/%2hd %2hd:%2hd:%2hd:%3hd", &stValue.wYear, &stValue.wMonth, &stValue.wDay, &stValue.wHour, &stValue.wMinute, &stValue.wSecond, &stValue.wMilliseconds );
if ( 1 == cItems ) cItems = swscanf( phrase, L"%4hd-%2hd-%2hd %2hd:%2hd:%2hd:%3hd", &stValue.wYear, &stValue.wMonth, &stValue.wDay, &stValue.wHour, &stValue.wMinute, &stValue.wSecond, &stValue.wMilliseconds );
if( cItems != 3 && cItems != 6 && cItems != 7) THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
// // Make a sensible split for Year 2000 using the user's system settings //
if ( stValue.wYear < 100 ) { DWORD dwYearHigh = 0; if ( 0 == GetCalendarInfo ( _locale, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER, 0, 0, &dwYearHigh ) ) { THROW ( CException () ); }
if ( ( dwYearHigh < 99 ) || ( dwYearHigh > 9999 ) ) dwYearHigh = 2029;
WORD wMaxDecade = (WORD) dwYearHigh % 100; WORD wMaxCentury = (WORD) dwYearHigh - wMaxDecade; if ( stValue.wYear <= wMaxDecade ) stValue.wYear += wMaxCentury; else stValue.wYear += ( wMaxCentury - 100 ); }
if( !SystemTimeToFileTime( &stValue, &ft ) ) THROW( CParserException( QPARSE_E_EXPECTING_DATE ) ); } } //ParseDateTime
//+--------------------------------------------------------------------------- // // Member: CValueParser::CheckForRelativeDate, private // // Synopsis: Attempts to parse a relative date expression. If successful, // it fills in the FILETIME structure with the calculated // absolute date. // // Notes: Returns TRUE if the phrase is recognized as a relative // date (i.e., it begins with a '-'). Otherwise, returns FALSE. // The format of a relative date is // "-"{INTEGER("h"|"n"|"s"|"y"|"q"|"m"|"d"|"w")}* // Case is not significant. // // Arguments: phrase -- pointer to the phrase to parse // ft -- reference to the FILETIME structure to fill in // with the result // // History: 26-May-94 t-jeffc Created // 02-Mar-95 t-colinb Moved from CQueryParser to // be more accessible // 22-Jan-97 KyleP Fix local/UTC discrepancy // //----------------------------------------------------------------------------
BOOL CValueParser::CheckForRelativeDate( WCHAR const * phrase, FILETIME & ft ) { if( *phrase++ == L'-' ) { SYSTEMTIME st; LARGE_INTEGER liLocal; LONGLONG llTicksInADay = ((LONGLONG)10000000) * ((LONGLONG)3600) * ((LONGLONG) 24); LONGLONG llTicksInAHour = ((LONGLONG) 10000000) * ((LONGLONG)3600); int iMonthDays[12] = {1,-1,1,0,1,0,1,1,0,1,0,1}; int iLoopValue, iPrevMonth, iPrevQuarter, iQuarterOffset; WORD wYear, wDayOfMonth, wStartDate;
// //Obtain local time and convert it to file time //Copy the filetime to largeint data struct //
GetSystemTime(&st); if(!SystemTimeToFileTime(&st, &ft)) THROW( CParserException( QPARSE_E_INVALID_LITERAL )); liLocal.LowPart = ft.dwLowDateTime; liLocal.HighPart = ft.dwHighDateTime; LONGLONG llRelDate = (LONGLONG)0; for( ;; ) { // eat white space while( iswspace( *phrase ) ) phrase++;
if( *phrase == 0 ) break;
// parse the number WCHAR * pwcEnd; LONG lValue = wcstol( phrase, &pwcEnd, 10 );
if( lValue < 0 ) THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
// eat white space phrase = pwcEnd; while( iswspace( *phrase ) ) phrase++;
// grab the unit char & subtract the appropriate amount WCHAR wcUnit = *phrase++; switch( wcUnit ) { case L'y': case L'Y': lValue *= 4; // Fall through and handle year like 4 quarters
case L'q': case L'Q': lValue *= 3; // Fall through and handle quarters like 3 months
case L'm': case L'M': // Getting the System time to determine the day and month.
if(!FileTimeToSystemTime(&ft, &st)) { THROW(CParserException(QPARSE_E_INVALID_LITERAL)); } wStartDate = st.wDay; wDayOfMonth = st.wDay; iLoopValue = lValue; while(iLoopValue) { // Subtracting to the end of previous month llRelDate = llTicksInADay * ((LONGLONG)(wDayOfMonth)); liLocal.QuadPart -= llRelDate; ft.dwLowDateTime = liLocal.LowPart; ft.dwHighDateTime = liLocal.HighPart; SYSTEMTIME stTemp; if(!FileTimeToSystemTime(&ft, &stTemp)) { THROW(CParserException(QPARSE_E_INVALID_LITERAL)); } // // if the end of previous month is greated then start date then we subtract to back up to the // start date. This will take care of 28/29 Feb(backing from 30/31 by 1 month). // if(stTemp.wDay > wStartDate) { llRelDate = llTicksInADay * ((LONGLONG)(stTemp.wDay - wStartDate)); liLocal.QuadPart -= llRelDate; ft.dwLowDateTime = liLocal.LowPart; ft.dwHighDateTime = liLocal.HighPart; // Getting the date into stTemp for further iteration if(!FileTimeToSystemTime(&ft, &stTemp)) { THROW( CParserException( QPARSE_E_INVALID_LITERAL )); } } wDayOfMonth = stTemp.wDay; iLoopValue--; } //End While
break;
case L'w': case L'W': lValue *= 7;
case L'd': case L'D': llRelDate = llTicksInADay * ((LONGLONG)lValue); liLocal.QuadPart -= llRelDate; ft.dwLowDateTime = liLocal.LowPart; ft.dwHighDateTime = liLocal.HighPart; break;
case L'h': case L'H': llRelDate = llTicksInAHour * ((LONGLONG)lValue); liLocal.QuadPart -= llRelDate; ft.dwLowDateTime = liLocal.LowPart; ft.dwHighDateTime = liLocal.HighPart; break;
case L'n': case L'N': llRelDate = ((LONGLONG)10000000) * ((LONGLONG)60) * ((LONGLONG)lValue) ; liLocal.QuadPart -= llRelDate; ft.dwLowDateTime = liLocal.LowPart; ft.dwHighDateTime = liLocal.HighPart; break;
case L's': case L'S': llRelDate = ((LONGLONG)10000000) * ((LONGLONG)lValue); liLocal.QuadPart -= llRelDate; ft.dwLowDateTime = liLocal.LowPart; ft.dwHighDateTime = liLocal.HighPart; break;
default: THROW( CParserException( QPARSE_E_EXPECTING_DATE ) ); }
} // for( ;; )
return TRUE; } else { return FALSE; } }
%}
%start query %%
/*** *** Tripolish YACC grammar *** *** Note - left recursion (i.e. A: A,B) used throughout because yacc *** handles it more efficiently. *** ***/ query: AndTerm { $$ = $1; } | query _OR AndTerm { AssertReq($1); AssertReq($3);
XDbRestriction prstQuery($1); XDbRestriction prstTerm($3); _setRst.Remove( $1 ); _setRst.Remove( $3 );
BOOL fAcquireQuery = FALSE;
XDbBooleanNodeRestriction prstNew; if (DBOP_or == $1->GetCommandType()) { // add right term & release its smart pointer ((CDbBooleanNodeRestriction *)($1))->AppendChild( prstTerm.GetPointer() ); prstTerm.Acquire(); fAcquireQuery = TRUE; $$ = prstQuery.GetPointer(); } else { // create smart Or node prstNew.Set( new CDbBooleanNodeRestriction( DBOP_or ) ); if( 0 == prstNew.GetPointer() ) THROW( CException( E_OUTOFMEMORY ) );
prstNew->SetWeight(MAX_QUERY_RANK);
// add left term & release its smart pointer prstNew->AppendChild( prstQuery.GetPointer() ); prstQuery.Acquire();
// add right term & release its smart pointer prstNew->AppendChild( prstTerm.GetPointer() ); prstTerm.Acquire();
$$ = prstNew.GetPointer(); }
_setRst.Add( $$ );
if ( fAcquireQuery ) prstQuery.Acquire(); else prstNew.Acquire();
} | _NOT query {
AssertReq($2);
XDbRestriction prstQuery($2); _setRst.Remove( $2 );
// Create not node
XDbBooleanNodeRestriction prstNew( new CDbBooleanNodeRestriction( DBOP_not ) ); if( 0 == prstNew.GetPointer() ) THROW( CException( E_OUTOFMEMORY ) );
prstNew->SetWeight(MAX_QUERY_RANK);
// add right term and release its smart pointer prstNew->AppendChild( prstQuery.GetPointer() ); prstQuery.Acquire();
$$ = prstNew.GetPointer(); _setRst.Add( $$ ); prstNew.Acquire(); } ;
AndTerm: NearTerm { $$ = $1;}
| _NOT PropTerm { AssertReq($2);
XDbRestriction prstTerm($2); _setRst.Remove( $2 );
// Create not node
XDbBooleanNodeRestriction prstNew( new CDbBooleanNodeRestriction( DBOP_not ) ); if( 0 == prstNew.GetPointer() ) THROW( CException( E_OUTOFMEMORY ) );
prstNew->SetWeight(MAX_QUERY_RANK);
// add right term and release its smart pointer prstNew->AppendChild( prstTerm.GetPointer() ); prstTerm.Acquire();
$$ = prstNew.GetPointer(); _setRst.Add( $$ ); prstNew.Acquire(); } | AndTerm _AND NearTerm { AssertReq($1); AssertReq($3);
XDbRestriction prstQuery($1); XDbRestriction prstTerm($3); _setRst.Remove( $1 ); _setRst.Remove( $3 );
BOOL fAcquireQuery = FALSE; XDbBooleanNodeRestriction prstNew; if (DBOP_and == $1->GetCommandType()) { // add right term & release its smart pointer ((CDbBooleanNodeRestriction *)($1))->AppendChild( prstTerm.GetPointer() ); prstTerm.Acquire(); fAcquireQuery = TRUE; $$ = prstQuery.GetPointer(); } else { // create smart And node prstNew.Set( new CDbBooleanNodeRestriction( DBOP_and ) ); if( prstNew.GetPointer() == 0 ) THROW( CException( E_OUTOFMEMORY ) );
prstNew->SetWeight(MAX_QUERY_RANK);
// add left term & release its smart pointer prstNew->AppendChild( prstQuery.GetPointer() ); prstQuery.Acquire();
// add right term & release its smart pointer prstNew->AppendChild( prstTerm.GetPointer() ); prstTerm.Acquire();
$$ = prstNew.GetPointer(); }
_setRst.Add( $$ );
if ( fAcquireQuery ) prstQuery.Acquire(); else prstNew.Acquire(); } | AndTerm _AND _NOT NearTerm { AssertReq($1); AssertReq($4);
XDbRestriction prstQuery($1); XDbRestriction prstTerm($4); _setRst.Remove( $1 ); _setRst.Remove( $4 );
// create smart Not node XDbNotRestriction prstNot( new CDbNotRestriction ); if( prstNot.GetPointer() == 0 ) THROW( CException( E_OUTOFMEMORY ) );
prstNot->SetWeight(MAX_QUERY_RANK);
// set child of Not node & release smart factor pointer prstNot->SetChild( prstTerm.GetPointer() ); prstTerm.Acquire();
BOOL fAcquireQuery = FALSE;
XDbBooleanNodeRestriction prstNew; if (DBOP_and == $1->GetCommandType()) { // add right term & release its smart pointer ((CDbBooleanNodeRestriction *)($1))->AppendChild( prstNot.GetPointer() ); prstNot.Acquire();
$$ = prstQuery.GetPointer(); fAcquireQuery = TRUE; } else { // create smart And node prstNew.Set( new CDbBooleanNodeRestriction( DBOP_and ) ); if( prstNew.GetPointer() == 0 ) THROW( CException( E_OUTOFMEMORY ) );
prstNew->SetWeight(MAX_QUERY_RANK);
// add left term & release its smart pointer prstNew->AppendChild( prstQuery.GetPointer() ); prstQuery.Acquire();
// add right term & release its smart pointer prstNew->AppendChild( prstNot.GetPointer() ); prstNot.Acquire();
$$ = prstNew.GetPointer(); }
_setRst.Add( $$ );
if ( fAcquireQuery ) prstQuery.Acquire(); else prstNew.Acquire(); } ;
NearTerm: CoerceTerm { $$ = $1; } | NearTerm _NEAR CoerceTerm { // uses defaults
AssertReq($1); AssertReq($3);
XDbRestriction prstLeft($1); XDbRestriction prstRight($3); _setRst.Remove( $1 ); _setRst.Remove( $3 );
BOOL fAcquireLeft = FALSE;
XDbProximityNodeRestriction prstNew;
if (DBOP_content_proximity == $1->GetCommandType() && 50 == ((CDbProximityNodeRestriction *)$1)->GetProximityDistance() && PROXIMITY_UNIT_WORD == ((CDbProximityNodeRestriction *)$1)->GetProximityUnit()) { // add right term & release its smart pointer ((CDbProximityNodeRestriction *)$1)->AppendChild( prstRight.GetPointer() ); prstRight.Acquire();
$$ = prstLeft.GetPointer(); fAcquireLeft = TRUE; } else { // create smart Prox node prstNew.Set(new CDbProximityNodeRestriction()); // uses defaults
if ( prstNew.IsNull() || !prstNew->IsValid() ) THROW( CException( E_OUTOFMEMORY ) );
// add left phrase & release its smart pointer prstNew->AppendChild( prstLeft.GetPointer() ); prstLeft.Acquire();
// add right term & release its smart pointer prstNew->AppendChild( prstRight.GetPointer() ); prstRight.Acquire();
$$ = prstNew.GetPointer(); }
_setRst.Add( $$ );
if ( fAcquireLeft ) prstLeft.Acquire(); else prstNew.Acquire(); } | NearTerm _NEARDIST _NEARUNIT _NEAR_END CoerceTerm { AssertReq($1); AssertReq($2); AssertReq($3); AssertReq($5);
XDbRestriction prstLeft($1); XDbRestriction prstRight($5); _setRst.Remove( $1 ); _setRst.Remove( $5 );
WCHAR * pwcEnd; ULONG ulValue = wcstol( $2, &pwcEnd, 10 ); ULONG ulUnit;
if (L'w' == *$3) ulUnit = PROXIMITY_UNIT_WORD; else if (L's' == *$3) ulUnit = PROXIMITY_UNIT_SENTENCE; else if (L'p' == *$3) ulUnit = PROXIMITY_UNIT_PARAGRAPH; else if (L'c' == *$3) ulUnit = PROXIMITY_UNIT_CHAPTER;
BOOL fAcquireLeft = FALSE; XDbProximityNodeRestriction prstNew;
if (DBOP_content_proximity == $1->GetCommandType() && ulValue == ((CDbProximityNodeRestriction *)$1)->GetProximityDistance() && ulUnit == ((CDbProximityNodeRestriction *)$1)->GetProximityUnit()) { // add right term & release its smart pointer ((CDbProximityNodeRestriction *)$1)->AppendChild( prstRight.GetPointer() ); prstRight.Acquire();
$$ = prstLeft.GetPointer(); fAcquireLeft = TRUE; } else { // create smart Prox node prstNew.Set(new CDbProximityNodeRestriction(ulUnit, ulValue));
if( prstNew.IsNull() || !prstNew->IsValid() ) THROW( CException( E_OUTOFMEMORY ) );
// add left phrase & release its smart pointer prstNew->AppendChild( prstLeft.GetPointer() ); prstLeft.Acquire();
// add right term & release its smart pointer prstNew->AppendChild( prstRight.GetPointer() ); prstRight.Acquire();
$$ = prstNew.GetPointer(); }
_setRst.Add( $$ );
if ( fAcquireLeft ) prstLeft.Acquire(); else prstNew.Acquire(); } ;
CoerceTerm: Gen NestTerm GenEnd { $$ = $2; } | Gen _COERCE Gen NestTerm GenEnd { AssertReq($4); XDbRestriction prstQuery($4);
$4->SetWeight(MAX_QUERY_RANK); $$ = prstQuery.Acquire(); } | Gen _WEIGHT Gen NestTerm GenEnd { AssertReq($2); AssertReq($4); XDbRestriction prstQuery($4);
WCHAR * pwcEnd; double dWeight = wcstod( $2, &pwcEnd ); if ( dWeight > 1.0 ) THROW( CParserException( QPARSE_E_WEIGHT_OUT_OF_RANGE ) ); LONG lWeight = (LONG)(dWeight * MAX_QUERY_RANK); $4->SetWeight(lWeight); $$ = prstQuery.Acquire(); } ;
Gen: /* empty */ { $$ = 0; } | _GENPREFIX { SetCurrentGenerate(GENERATE_METHOD_PREFIX); $$ = GENERATE_METHOD_PREFIX; } | _GENINFLECT { SetCurrentGenerate(GENERATE_METHOD_INFLECT); $$ = GENERATE_METHOD_INFLECT; } ;
GenEnd: /* empty */ { $$ = GENERATE_METHOD_EXACT; } | _GENNORMAL { // don't set the generate method to 0 here. Doing so will // reset the method before it gets used. $$ = GENERATE_METHOD_EXACT; }
NestTerm: VectorTerm { $$ = $1; } | Term { $$ = $1; } | Open query Close { $$ = $2; } ;
VectorTerm: VectorSpec _VECTOR_END { $$ = $1; }
VectorSpec: _VEMETHOD _VE query { AssertReq($1); AssertReq($3);
XDbRestriction prstQuery($3); _setRst.Remove( $3 );
ULONG rankMethod = VECTOR_RANK_JACCARD; // default if nothing else matches
if ( 0 == _wcsicmp( L"jaccard", $1) ) { rankMethod = VECTOR_RANK_JACCARD; } else if ( 0 == _wcsicmp( L"dice", $1) ) { rankMethod = VECTOR_RANK_DICE; } else if ( 0 == _wcsicmp( L"inner", $1) ) { rankMethod = VECTOR_RANK_INNER; } else if ( 0 == _wcsicmp( L"max", $1) ) { rankMethod = VECTOR_RANK_MAX; } else if ( 0 == _wcsicmp( L"min", $1) ) { rankMethod = VECTOR_RANK_MIN; } else { THROW( CException( QPARSE_E_INVALID_RANKMETHOD ) ); }
// create smart Vector node XDbVectorRestriction prstNew( new CDbVectorRestriction( rankMethod ) );
if ( prstNew.IsNull() || !prstNew->IsValid() ) { THROW( CException( E_OUTOFMEMORY ) ); }
// add expression & release its smart pointer prstNew->AppendChild( prstQuery.GetPointer() ); prstQuery.Acquire();
// Let the next vector element start off with a clean slate... // We don't want the current element's property and genmethod // to rub off on it. InitState();
$$ = prstNew.GetPointer(); _setRst.Add( $$ ); prstNew.Acquire(); } | VectorSpec _VE query { AssertReq($1); AssertReq($3);
XDbRestriction prstLeft($1); XDbRestriction prstRight($3); _setRst.Remove( $1 ); _setRst.Remove( $3 );
// add right term & release its smart pointer ((CDbVectorRestriction *)($1))->AppendChild( prstRight.GetPointer() ); prstRight.Acquire();
// Let the next vector element start off with a clean slate... // We don't want the current element's property and genmethod // to rub off on it. InitState();
$$ = prstLeft.GetPointer(); _setRst.Add( $$ ); prstLeft.Acquire(); } ;
Open: _OPEN { SaveState(); $$ = 0; } Close: _CLOSE { RestoreState(); $$ = 0; }
Term: PropTerm { $$ = $1; }
| Property Contains _PHRASE ShortGen PropEnd { $$ = BuildPhrase($3, $4); _setRst.Add( $$ ); } | Property Contains _PHRASE PropEnd { $$ = BuildPhrase($3, 0); _setRst.Add( $$ ); } | Property Contains Gen _PHRASE GenEnd PropEnd { $$ = BuildPhrase($4, $3); _setRst.Add( $$ ); } | Property Contains query { $$ = $3; } | Property Contains _FREETEXT ShortGen PropEnd { AssertReq($3); CDbColId *pps; DBTYPE dbType; GetCurrentProperty(&pps, &dbType);
// We used the property. Now pop it off if need be if (fDeferredPop) PopProperty();
// Clear generation method so it won't rub off on the following phrase SetCurrentGenerate(GENERATE_METHOD_EXACT);
// generation method not used - if it's there, ignore it // (already stripped from longhand version, but not from // shorthand version LPWSTR pLast = $3 + wcslen($3) -1; if ( L'*' == *pLast) // prefix *pLast-- = L'\0'; if ( L'*' == *pLast) // inflect *pLast-- = L'\0';
XDbNatLangRestriction pRest ( new CDbNatLangRestriction ($3, *pps, _lcid)); if ( pRest.IsNull() || !pRest->IsValid() ) THROW( CException( E_OUTOFMEMORY ) );
$$ = pRest.GetPointer(); _setRst.Add( $$ ); pRest.Acquire(); } ;
PropTerm: Property Matches _REGEX PropEnd { AssertReq($3);
CDbColId *pps; DBTYPE dbType;
GetCurrentProperty(&pps, &dbType);
// We used the property. Now pop it off if need be if (fDeferredPop) PopProperty();
if ( ( ( DBTYPE_WSTR|DBTYPE_BYREF ) != dbType ) && ( ( DBTYPE_STR|DBTYPE_BYREF ) != dbType ) && ( VT_BSTR != dbType ) && ( VT_LPWSTR != dbType ) && ( VT_LPSTR != dbType ) ) THROW( CParserException( QPARSE_E_EXPECTING_REGEX_PROPERTY ) );
if( $3 == 0 ) THROW( CParserException( QPARSE_E_EXPECTING_REGEX ) );
// create smart Property node XDbPropertyRestriction prstProp( new CDbPropertyRestriction ); if( prstProp.GetPointer() == 0 ) THROW( CException( E_OUTOFMEMORY ) );
prstProp->SetRelation(DBOP_like); // LIKE relation
if ( ( ! prstProp->SetProperty( *pps ) ) || ( ! prstProp->SetValue( $3 ) ) || ( ! prstProp->IsValid() ) ) THROW( CException( E_OUTOFMEMORY ) );
// release & return smart Property node $$ = prstProp.GetPointer(); _setRst.Add( $$ ); prstProp.Acquire(); }
| Property Op Value PropEnd { AssertReq($2); AssertReq($3); XPtr<CStorageVariant> pStorageVar( $3 ); _setStgVar.Remove( $3 );
CDbColId *pps; DBTYPE dbType; GetCurrentProperty(&pps, &dbType);
// We used the property. Now pop it off if need be if (fDeferredPop) PopProperty();
// create smart Property node XDbPropertyRestriction prstProp( new CDbPropertyRestriction ); if( prstProp.GetPointer() == 0 ) THROW( CException( E_OUTOFMEMORY ) );
if (! prstProp->SetProperty( *pps ) ) THROW( CException( E_OUTOFMEMORY ) );
// don't allow @contents <relop> X -- it's too expensive and we'll // never find any hits anyway (until we implement this feature)
if ( *pps == psContents ) THROW( CParserException( QPARSE_E_EXPECTING_PHRASE ) );
prstProp->SetRelation( $2 );
if ( 0 != pStorageVar.GetPointer() ) { // This should always be the case - else PropValueParser would have thrown
if ( ! ( ( prstProp->SetValue( pStorageVar.GetReference() ) ) && ( prstProp->IsValid() ) ) ) THROW( CException( E_OUTOFMEMORY ) ); } $$ = prstProp.GetPointer(); _setRst.Add( $$ ); prstProp.Acquire(); } ;
Property: /* empty */ { $$ = 0; } | _PROPNAME { PushProperty($1); $$ = 0; } ;
PropEnd: /* empty */ { fDeferredPop = FALSE; $$ = 0; } | _PROPEND { // When PropEnd is matched, the action of using the property // hasn't yet taken place. So popping the property right now // will cause the property to be unavailable when the action // is performed. Instead, pop it off after it has been used. fDeferredPop = TRUE; $$ = 0; } ;
Op: _EQ { $$ = DBOP_equal;} | _NE { $$ = DBOP_not_equal;} | _GT { $$ = DBOP_greater;} | _GTE { $$ = DBOP_greater_equal;} | _LT { $$ = DBOP_less;} | _LTE { $$ = DBOP_less_equal;} | _ALLOF { $$ = DBOP_allbits;} | _SOMEOF { $$ = DBOP_anybits;} | _EQSOME { $$ = DBOP_equal_any;} | _NESOME { $$ = DBOP_not_equal_any;} | _GTSOME { $$ = DBOP_greater_any;} | _GTESOME { $$ = DBOP_greater_equal_any;} | _LTSOME { $$ = DBOP_less_any;} | _LTESOME { $$ = DBOP_less_equal_any;} | _ALLOFSOME { $$ = DBOP_allbits_any;} | _SOMEOFSOME { $$ = DBOP_anybits_any;} | _EQALL { $$ = DBOP_equal_all;} | _NEALL { $$ = DBOP_not_equal_all;} | _GTALL { $$ = DBOP_greater_all;} | _GTEALL { $$ = DBOP_greater_equal_all;} | _LTALL { $$ = DBOP_less_all;} | _LTEALL { $$ = DBOP_less_equal_all;} | _ALLOFALL { $$ = DBOP_allbits_all;} | _SOMEOFALL { $$ = DBOP_anybits_all;} ;
Matches: /* empty */ { $$ = 0; } | _EQ { $$ = DBOP_equal; }
Value: _PHRASE { CDbColId *pps; DBTYPE dbType; GetCurrentProperty(&pps, &dbType);
CValueParser PropValueParser( FALSE, dbType, _lcid ); StripQuotes($1); PropValueParser.AddValue( $1 );
$$ = PropValueParser.GetStgVariant(); _setStgVar.Add( $$ ); PropValueParser.AcquireStgVariant(); } | _FREETEXT { CDbColId *pps; DBTYPE dbType; GetCurrentProperty(&pps, &dbType);
CValueParser PropValueParser( FALSE, dbType, _lcid ); PropValueParser.AddValue( $1 );
$$ = PropValueParser.GetStgVariant(); _setStgVar.Add( $$ ); PropValueParser.AcquireStgVariant(); } | VectorValue { $$ = $1; }
;
VectorValue: EmptyVector { XPtr <CValueParser> pPropValueParser ( $1 ); _setValueParser.Remove( $1 ); $$ = $1->GetStgVariant(); _setStgVar.Add( $$ ); $1->AcquireStgVariant(); } | SingletVector { XPtr <CValueParser> pPropValueParser ( $1 ); _setValueParser.Remove( $1 ); $$ = $1->GetStgVariant(); _setStgVar.Add( $$ ); $1->AcquireStgVariant(); } | MultiVector _VE_END { XPtr <CValueParser> pPropValueParser ( $1 ); _setValueParser.Remove( $1 ); $$ = $1->GetStgVariant(); _setStgVar.Add( $$ ); $1->AcquireStgVariant(); }
EmptyVector: _OPEN _CLOSE { CDbColId *pps; DBTYPE dbType; GetCurrentProperty(&pps, &dbType);
XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) ); if( pPropValueParser.GetPointer() == 0 ) THROW( CException( E_OUTOFMEMORY ) );
$$ = pPropValueParser.GetPointer(); _setValueParser.Add( $$ ); pPropValueParser.Acquire(); }
SingletVector: _OPEN _PHRASE _CLOSE { AssertReq($2);
CDbColId *pps; DBTYPE dbType; GetCurrentProperty(&pps, &dbType);
XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) ); if( pPropValueParser.GetPointer() == 0 ) THROW( CException( E_OUTOFMEMORY ) );
StripQuotes($2); pPropValueParser->AddValue( $2 );
$$ = pPropValueParser.GetPointer(); _setValueParser.Add( $$ ); pPropValueParser.Acquire(); } | _OPEN _FREETEXT _CLOSE { AssertReq($2);
CDbColId *pps; DBTYPE dbType; GetCurrentProperty(&pps, &dbType);
XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) ); if( pPropValueParser.GetPointer() == 0 ) THROW( CException( E_OUTOFMEMORY ) );
pPropValueParser->AddValue( $2 );
$$ = pPropValueParser.GetPointer(); _setValueParser.Add( $$ ); pPropValueParser.Acquire(); }
MultiVector: _VECTORELEMENT _VECTORELEMENT { AssertReq($1); AssertReq($2);
CDbColId *pps; DBTYPE dbType; GetCurrentProperty(&pps, &dbType);
XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) ); if( pPropValueParser.GetPointer() == 0 ) THROW( CException( E_OUTOFMEMORY ) );
pPropValueParser->AddValue( $1 ); pPropValueParser->AddValue( $2 );
$$ = pPropValueParser.GetPointer(); _setValueParser.Add( $$ ); pPropValueParser.Acquire(); }
| MultiVector _VECTORELEMENT { AssertReq($1); AssertReq($2);
$1->AddValue($2);
$$ = $1; } ;
Contains: /* empty */ { $$ = 0; } | _CONTAINS { $$ = 0; } ;
ShortGen: /* empty */ { $$ = 0; } | _SHGENPREFIX { $$ = 1; } | _SHGENINFLECT { $$ = 2; } ;
|