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.
244 lines
5.9 KiB
244 lines
5.9 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 1998, Microsoft Corp. All rights reserved.
|
|
//
|
|
// FILE
|
|
//
|
|
// xprparse.cpp
|
|
//
|
|
// SYNOPSIS
|
|
//
|
|
// This file implements the function IASParseExpression.
|
|
//
|
|
// MODIFICATION HISTORY
|
|
//
|
|
// 02/06/1998 Original version.
|
|
// 05/21/1999 Remove old style trace.
|
|
// 03/23/2000 Use two quotes to escape a quote.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <ias.h>
|
|
|
|
#include <ExprBuilder.h>
|
|
#include <Parser.h>
|
|
#include <xprparse.h>
|
|
|
|
//////////
|
|
// Struct for converting an identifier to a logical token.
|
|
//////////
|
|
struct KeyWord
|
|
{
|
|
PCWSTR identifier;
|
|
IAS_LOGICAL_TOKEN token;
|
|
};
|
|
|
|
//////////
|
|
// Table of keywords. These must be sorted alphabetically.
|
|
//////////
|
|
const KeyWord KEYWORDS[] =
|
|
{
|
|
{ L"AND", IAS_LOGICAL_AND },
|
|
{ L"FALSE", IAS_LOGICAL_FALSE },
|
|
{ L"NOT", IAS_LOGICAL_NOT },
|
|
{ L"OR", IAS_LOGICAL_OR },
|
|
{ L"TRUE", IAS_LOGICAL_TRUE },
|
|
{ L"XOR", IAS_LOGICAL_XOR },
|
|
{ NULL, IAS_LOGICAL_NUM_TOKENS }
|
|
};
|
|
|
|
//////////
|
|
// Returns the IAS_LOGICAL_TOKEN equivalent for 'key' or IAS_LOGICAL_NUM_TOKENS
|
|
// if no such equivalent exists.
|
|
//////////
|
|
IAS_LOGICAL_TOKEN findKeyWord(PCWSTR key) throw ()
|
|
{
|
|
// We'll use a linear search since the table is so small.
|
|
for (const KeyWord* i = KEYWORDS; i->identifier; ++i)
|
|
{
|
|
int cmp = _wcsicmp(key, i->identifier);
|
|
|
|
// Did we find it ?
|
|
if (cmp == 0) { return i->token; }
|
|
|
|
// Did we we go past it ?
|
|
if (cmp < 0) { break; }
|
|
}
|
|
|
|
return IAS_LOGICAL_NUM_TOKENS;
|
|
}
|
|
|
|
//////////
|
|
// Special characters for parsing.
|
|
//////////
|
|
const WCHAR WHITESPACE[] = L" \t\n";
|
|
const WCHAR TOKEN_DELIMITERS[] = L" \t\n()";
|
|
|
|
//////////
|
|
// Parse a chunk of expression text and add it to the ExpressionBuilder.
|
|
//////////
|
|
void addExpressionString(ExpressionBuilder& expression, PCWSTR szExpression)
|
|
{
|
|
//////////
|
|
// Make a local copy because parser can temporarily modify the string.
|
|
//////////
|
|
|
|
size_t len = sizeof(WCHAR) * (wcslen(szExpression) + 1);
|
|
Parser p((PWSTR)memcpy(_alloca(len), szExpression, len));
|
|
|
|
//////////
|
|
// Loop through the expression until we hit the null-terminator.
|
|
//////////
|
|
while (*p.skip(WHITESPACE) != L'\0')
|
|
{
|
|
//////////
|
|
// Parentheses are handled separately since they don't have to be
|
|
// delimited by whitespace.
|
|
//////////
|
|
if (*p == L'(')
|
|
{
|
|
expression.addToken(IAS_LOGICAL_LEFT_PAREN);
|
|
++p;
|
|
}
|
|
else if (*p == L')')
|
|
{
|
|
expression.addToken(IAS_LOGICAL_RIGHT_PAREN);
|
|
++p;
|
|
}
|
|
else
|
|
{
|
|
// Get the next token.
|
|
const wchar_t* token = p.findToken(TOKEN_DELIMITERS);
|
|
|
|
// Check if it's a keyword.
|
|
IAS_LOGICAL_TOKEN keyWord = findKeyWord(token);
|
|
if (keyWord != IAS_LOGICAL_NUM_TOKENS)
|
|
{
|
|
// If it is a keyword, add it to the expression ...
|
|
expression.addToken(keyWord);
|
|
p.releaseToken();
|
|
}
|
|
else
|
|
{
|
|
// If it's not a keyword, it must be a condition object.
|
|
expression.addCondition(token);
|
|
p.releaseToken();
|
|
|
|
// Skip the leading parenthesis.
|
|
p.skip(WHITESPACE);
|
|
p.ignore(L'(');
|
|
|
|
// Skip the leading quote.
|
|
p.skip(WHITESPACE);
|
|
p.ignore(L'\"');
|
|
|
|
// We're now at the beginning of the condition text.
|
|
p.beginToken();
|
|
|
|
// Find the trailing quote, skipping any escaped characters.
|
|
while (p.findNext(L'\"')[1] == L'\"')
|
|
{
|
|
++p;
|
|
p.erase(1);
|
|
}
|
|
|
|
// Add the condition text.
|
|
expression.addConditionText(p.endToken());
|
|
p.releaseToken();
|
|
|
|
// Skip the trailing quote
|
|
p.ignore(L'\"');
|
|
|
|
// Skip the trailing parenthesis.
|
|
p.skip(WHITESPACE);
|
|
p.ignore(L')');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IASParseExpression(
|
|
PCWSTR szExpression,
|
|
VARIANT* pVal
|
|
)
|
|
{
|
|
if (szExpression == NULL || pVal == NULL) { return E_INVALIDARG; }
|
|
|
|
VariantInit(pVal);
|
|
|
|
try
|
|
{
|
|
ExpressionBuilder expression;
|
|
|
|
addExpressionString(expression, szExpression);
|
|
|
|
expression.detach(pVal);
|
|
}
|
|
catch (Parser::ParseError)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
CATCH_AND_RETURN()
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
WINAPI
|
|
IASParseExpressionEx(
|
|
IN VARIANT* pvExpression,
|
|
OUT VARIANT* pVal
|
|
)
|
|
{
|
|
if (pvExpression == NULL || pVal == NULL) { return E_INVALIDARG; }
|
|
|
|
// If the VARIANT contains a single BSTR, we can just use the method
|
|
// defined above.
|
|
if (V_VT(pvExpression) == VT_BSTR)
|
|
{
|
|
return IASParseExpression(V_BSTR(pvExpression), pVal);
|
|
}
|
|
|
|
VariantInit(pVal);
|
|
|
|
try
|
|
{
|
|
ExpressionBuilder expression;
|
|
|
|
if (V_VT(pvExpression) == VT_EMPTY)
|
|
{
|
|
// If the variant is empty, the expression is always false.
|
|
expression.addToken(IAS_LOGICAL_FALSE);
|
|
}
|
|
else
|
|
{
|
|
CVariantVector<VARIANT> values(pvExpression);
|
|
|
|
for (size_t i = 0; i < values.size(); ++i)
|
|
{
|
|
// If we have more than one value, join them by AND's.
|
|
if (i != 0) { expression.addToken(IAS_LOGICAL_AND); }
|
|
|
|
if (V_VT(&values[i]) != VT_BSTR)
|
|
{
|
|
_com_issue_error(DISP_E_TYPEMISMATCH);
|
|
}
|
|
|
|
addExpressionString(expression, V_BSTR(&values[i]));
|
|
}
|
|
}
|
|
|
|
expression.detach(pVal);
|
|
}
|
|
catch (Parser::ParseError)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
CATCH_AND_RETURN()
|
|
|
|
return S_OK;
|
|
}
|