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.
2887 lines
71 KiB
2887 lines
71 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// C++ source expression evaluation.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 2001-2002.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "ntsdp.hpp"
|
|
|
|
#define DBG_TOKENS 0
|
|
#define DBG_TYPES 0
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// CppEvalExpression.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
char CppEvalExpression::s_EscapeChars[] = "?afvbntr\"'\\";
|
|
char CppEvalExpression::s_EscapeCharValues[] = "?\a\f\v\b\n\t\r\"'\\";
|
|
|
|
PCSTR CppEvalExpression::s_MultiTokens[] =
|
|
{
|
|
"EOF",
|
|
"identifier",
|
|
"integer literal",
|
|
"floating-point literal",
|
|
"char string literal",
|
|
"char literal",
|
|
"wchar string literal",
|
|
"wchar literal",
|
|
"debugger register",
|
|
"module name",
|
|
"MASM expression",
|
|
"Preprocessor function",
|
|
"==",
|
|
"!=",
|
|
"<=",
|
|
">=",
|
|
"&&",
|
|
"||",
|
|
"U+",
|
|
"U-",
|
|
"<<",
|
|
">>",
|
|
"address of",
|
|
"dereference",
|
|
"->",
|
|
".*",
|
|
"->*",
|
|
"/=",
|
|
"*=",
|
|
"%=",
|
|
"+=",
|
|
"-=",
|
|
"<<=",
|
|
">>=",
|
|
"&=",
|
|
"|=",
|
|
"^=",
|
|
"++",
|
|
"--",
|
|
"++",
|
|
"--",
|
|
"::",
|
|
"::~",
|
|
"sizeof",
|
|
"this",
|
|
"operator",
|
|
"new",
|
|
"delete",
|
|
"const",
|
|
"struct",
|
|
"class",
|
|
"union",
|
|
"enum",
|
|
"volatile",
|
|
"signed",
|
|
"unsigned",
|
|
"dynamic_cast",
|
|
"static_cast",
|
|
"const_cast",
|
|
"reinterpret_cast",
|
|
"typeid",
|
|
};
|
|
|
|
CppEvalExpression::CppEvalExpression(void)
|
|
: EvalExpression(DEBUG_EXPR_CPLUSPLUS,
|
|
"C++ source expressions",
|
|
"C++")
|
|
{
|
|
m_PreprocEval = FALSE;
|
|
}
|
|
|
|
CppEvalExpression::~CppEvalExpression(void)
|
|
{
|
|
}
|
|
|
|
PCSTR
|
|
CppEvalExpression::TokenImage(CppToken Token)
|
|
{
|
|
#define TOKIM_CHARS 8
|
|
static char s_CharImage[2 * TOKIM_CHARS];
|
|
static int s_CharImageIdx = 0;
|
|
|
|
C_ASSERT(DIMA(s_MultiTokens) == CppTokenCount - CPP_TOKEN_MULTI);
|
|
|
|
if (Token <= CppTokenError || Token >= CppTokenCount)
|
|
{
|
|
return NULL;
|
|
}
|
|
else if (Token < CPP_TOKEN_MULTI)
|
|
{
|
|
PSTR Image;
|
|
|
|
Image = s_CharImage + s_CharImageIdx;
|
|
s_CharImageIdx += 2;
|
|
if (s_CharImageIdx >= sizeof(s_CharImage))
|
|
{
|
|
s_CharImageIdx = 0;
|
|
}
|
|
Image[0] = (char)Token;
|
|
Image[1] = 0;
|
|
return Image;
|
|
}
|
|
else
|
|
{
|
|
return s_MultiTokens[Token - CPP_TOKEN_MULTI];
|
|
}
|
|
}
|
|
|
|
char
|
|
CppEvalExpression::GetStringChar(PBOOL Escaped)
|
|
{
|
|
char Ch;
|
|
PSTR Esc;
|
|
int V;
|
|
|
|
*Escaped = FALSE;
|
|
|
|
Ch = *m_Lex++;
|
|
if (!Ch)
|
|
{
|
|
m_Lex--;
|
|
EvalErrorDesc(SYNTAX, "EOF in literal");
|
|
}
|
|
else if (Ch == '\n' || Ch == '\r')
|
|
{
|
|
m_Lex--;
|
|
EvalErrorDesc(SYNTAX, "Newline in literal");
|
|
}
|
|
else if (Ch == '\\')
|
|
{
|
|
*Escaped = TRUE;
|
|
|
|
Ch = *m_Lex++;
|
|
if (!Ch)
|
|
{
|
|
EvalErrorDesc(SYNTAX, "EOF in literal");
|
|
}
|
|
else if (Ch == 'x')
|
|
{
|
|
// Hex character literal.
|
|
|
|
V = 0;
|
|
for (;;)
|
|
{
|
|
Ch = *m_Lex++;
|
|
if (!isxdigit(Ch))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (isupper(Ch))
|
|
{
|
|
Ch = (char)tolower(Ch);
|
|
}
|
|
|
|
V = V * 16 + (Ch >= 'a' ? Ch - 'a' + 10 : Ch - '0');
|
|
}
|
|
|
|
m_Lex--;
|
|
Ch = (char)V;
|
|
}
|
|
else if (IS_OCTAL_DIGIT(Ch))
|
|
{
|
|
// Octal character literal.
|
|
|
|
V = 0;
|
|
do
|
|
{
|
|
V = V * 8 + Ch - '0';
|
|
Ch = *m_Lex++;
|
|
} while (IS_OCTAL_DIGIT(Ch));
|
|
|
|
m_Lex--;
|
|
Ch = (char)V;
|
|
}
|
|
else
|
|
{
|
|
Esc = strchr(s_EscapeChars, Ch);
|
|
if (Esc == NULL)
|
|
{
|
|
EvalErrorDesc(SYNTAX, "Unknown escape character");
|
|
}
|
|
else
|
|
{
|
|
Ch = s_EscapeCharValues[Esc - s_EscapeChars];
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ch;
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::FinishFloat(LONG64 IntPart, int Sign)
|
|
{
|
|
double Val = (double)IntPart;
|
|
double Frac = 1;
|
|
char Ch;
|
|
|
|
Ch = *(m_Lex - 1);
|
|
if (Ch == '.')
|
|
{
|
|
for (;;)
|
|
{
|
|
Ch = *m_Lex++;
|
|
if (!isdigit(Ch))
|
|
{
|
|
break;
|
|
}
|
|
|
|
Frac /= 10;
|
|
Val += ((int)Ch - (int)'0') * Frac;
|
|
AddLexeme(Ch);
|
|
}
|
|
}
|
|
|
|
if (Ch == 'e' || Ch == 'E')
|
|
{
|
|
long Power = 0;
|
|
BOOL Neg = FALSE;
|
|
|
|
Ch = *m_Lex++;
|
|
if (Ch == '-' || Ch == '+')
|
|
{
|
|
AddLexeme(Ch);
|
|
if (Ch == '-')
|
|
{
|
|
Neg = TRUE;
|
|
}
|
|
Ch = *m_Lex++;
|
|
}
|
|
|
|
while (isdigit(Ch))
|
|
{
|
|
AddLexeme(Ch);
|
|
Power = Power * 10 + Ch - '0';
|
|
Ch = *m_Lex++;
|
|
}
|
|
|
|
if (Neg)
|
|
{
|
|
Power = -Power;
|
|
}
|
|
|
|
Val *= pow(10.0, Power);
|
|
}
|
|
|
|
m_Lex--;
|
|
|
|
BOOL Long = FALSE;
|
|
BOOL Float = FALSE;
|
|
|
|
for (;;)
|
|
{
|
|
if (*m_Lex == 'f' || *m_Lex == 'F')
|
|
{
|
|
Float = TRUE;
|
|
AddLexeme(*m_Lex++);
|
|
}
|
|
else if (*m_Lex == 'l' || *m_Lex == 'L')
|
|
{
|
|
Long = TRUE;
|
|
AddLexeme(*m_Lex++);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
ZeroMemory(&m_TokenValue, sizeof(m_TokenValue));
|
|
if (Long || !Float)
|
|
{
|
|
m_TokenValue.m_BaseType = DNTYPE_FLOAT64;
|
|
m_TokenValue.m_F64 = Val * Sign;
|
|
}
|
|
else
|
|
{
|
|
m_TokenValue.m_BaseType = DNTYPE_FLOAT32;
|
|
m_TokenValue.m_F32 = (float)(Val * Sign);
|
|
}
|
|
|
|
AddLexeme(0);
|
|
m_TokenValue.SetToNativeType(m_TokenValue.m_BaseType);
|
|
}
|
|
|
|
CppToken
|
|
CppEvalExpression::ReadNumber(int Sign)
|
|
{
|
|
ULONG64 IntVal;
|
|
char Ch, Nch;
|
|
BOOL Decimal = FALSE;
|
|
|
|
//
|
|
// Many number outputs use ` as a separator between
|
|
// the high and low parts of a 64-bit number. Ignore
|
|
// ` here to make it simple to use such values.
|
|
//
|
|
|
|
Ch = *(m_Lex - 1);
|
|
Nch = *m_Lex++;
|
|
if (Ch != '0' ||
|
|
(Nch != 'x' && Nch != 'X' && !IS_OCTAL_DIGIT(Nch)))
|
|
{
|
|
IntVal = Ch - '0';
|
|
Ch = Nch;
|
|
while (isdigit(Ch) || Ch == '`')
|
|
{
|
|
if (Ch != '`')
|
|
{
|
|
IntVal = IntVal * 10 + (Ch - '0');
|
|
}
|
|
AddLexeme(Ch);
|
|
Ch = *m_Lex++;
|
|
}
|
|
|
|
if (Ch == '.' || Ch == 'e' || Ch == 'E' || Ch == 'f' || Ch == 'F')
|
|
{
|
|
AddLexeme(Ch);
|
|
FinishFloat((LONG64)IntVal, Sign);
|
|
return CppTokenFloat;
|
|
}
|
|
|
|
Decimal = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Ch = Nch;
|
|
IntVal = 0;
|
|
if (Ch == 'x' || Ch == 'X')
|
|
{
|
|
AddLexeme(Ch);
|
|
for (;;)
|
|
{
|
|
Ch = *m_Lex++;
|
|
if (!isxdigit(Ch) && Ch != '`')
|
|
{
|
|
break;
|
|
}
|
|
|
|
AddLexeme(Ch);
|
|
if (Ch == '`')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (isupper(Ch))
|
|
{
|
|
Ch = (char)tolower(Ch);
|
|
}
|
|
IntVal = IntVal * 16 + (Ch >= 'a' ? Ch - 'a' + 10 : Ch - '0');
|
|
}
|
|
}
|
|
else if (IS_OCTAL_DIGIT(Ch))
|
|
{
|
|
do
|
|
{
|
|
AddLexeme(Ch);
|
|
if (Ch != '`')
|
|
{
|
|
IntVal = IntVal * 8 + (Ch - '0');
|
|
}
|
|
Ch = *m_Lex++;
|
|
}
|
|
while (IS_OCTAL_DIGIT(Ch) || Ch == '`');
|
|
}
|
|
}
|
|
|
|
m_Lex--;
|
|
|
|
BOOL Unsigned = FALSE, I64 = FALSE;
|
|
|
|
for (;;)
|
|
{
|
|
if (*m_Lex == 'l' || *m_Lex == 'L')
|
|
{
|
|
AddLexeme(*m_Lex++);
|
|
}
|
|
else if ((*m_Lex == 'i' || *m_Lex == 'I') &&
|
|
*(m_Lex + 1) == '6' && *(m_Lex + 2) == '4')
|
|
{
|
|
AddLexeme(*m_Lex++);
|
|
AddLexeme(*m_Lex++);
|
|
AddLexeme(*m_Lex++);
|
|
I64 = TRUE;
|
|
}
|
|
else if (*m_Lex == 'u' || *m_Lex == 'U')
|
|
{
|
|
AddLexeme(*m_Lex++);
|
|
Unsigned = TRUE;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
AddLexeme(0);
|
|
ZeroMemory(&m_TokenValue, sizeof(m_TokenValue));
|
|
|
|
// Constants are given the smallest type which can contain
|
|
// their value.
|
|
if (!Unsigned)
|
|
{
|
|
if (I64)
|
|
{
|
|
if (IntVal >= 0x8000000000000000)
|
|
{
|
|
// Value has to be an unsigned int64.
|
|
m_TokenValue.m_BaseType = DNTYPE_UINT64;
|
|
}
|
|
else
|
|
{
|
|
m_TokenValue.m_BaseType = DNTYPE_INT64;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (IntVal >= 0x8000000000000000)
|
|
{
|
|
// Value has to be an unsigned int64.
|
|
m_TokenValue.m_BaseType = DNTYPE_UINT64;
|
|
}
|
|
else if ((Decimal && IntVal >= 0x80000000) ||
|
|
(!Decimal && IntVal >= 0x100000000))
|
|
{
|
|
// Value has to be an int64.
|
|
m_TokenValue.m_BaseType = DNTYPE_INT64;
|
|
}
|
|
else if (IntVal >= 0x80000000)
|
|
{
|
|
// Value has to be an unsigned int.
|
|
m_TokenValue.m_BaseType = DNTYPE_UINT32;
|
|
}
|
|
else
|
|
{
|
|
m_TokenValue.m_BaseType = DNTYPE_INT32;
|
|
}
|
|
}
|
|
}
|
|
else if (!I64)
|
|
{
|
|
if (IntVal >= 0x100000000)
|
|
{
|
|
// Value has to be an unsigned int64.
|
|
m_TokenValue.m_BaseType = DNTYPE_UINT64;
|
|
}
|
|
else
|
|
{
|
|
m_TokenValue.m_BaseType = DNTYPE_UINT32;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_TokenValue.m_BaseType = DNTYPE_UINT64;
|
|
}
|
|
|
|
m_TokenValue.SetToNativeType(m_TokenValue.m_BaseType);
|
|
m_TokenValue.m_S64 = (LONG64)IntVal * Sign;
|
|
return CppTokenInteger;
|
|
}
|
|
|
|
CppToken
|
|
CppEvalExpression::Lex(void)
|
|
{
|
|
char Ch, Nch, Tch;
|
|
PSTR Single;
|
|
BOOL UnaryOp;
|
|
BOOL CharToken;
|
|
BOOL Escaped;
|
|
|
|
UnaryOp = m_AllowUnaryOp;
|
|
m_AllowUnaryOp = TRUE;
|
|
|
|
for (;;)
|
|
{
|
|
for (;;)
|
|
{
|
|
Ch = *m_Lex++;
|
|
if (IS_EOF(Ch))
|
|
{
|
|
m_Lex--;
|
|
StartLexeme();
|
|
m_LexemeSourceStart = m_Lex;
|
|
AddLexeme(0);
|
|
return CppTokenEof;
|
|
}
|
|
|
|
if (!isspace(Ch))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
StartLexeme();
|
|
m_LexemeSourceStart = m_Lex - 1;
|
|
AddLexeme(Ch);
|
|
|
|
Nch = *m_Lex;
|
|
|
|
/* String literals */
|
|
if (Ch == '\"' ||
|
|
(Ch == 'L' && Nch == '\"'))
|
|
{
|
|
BOOL Wide = FALSE;
|
|
|
|
if (Ch == 'L')
|
|
{
|
|
m_Lex++;
|
|
Wide = TRUE;
|
|
}
|
|
|
|
// Store the translated literal in
|
|
// the lexeme rather than the source text to
|
|
// avoid having two large buffers where one is
|
|
// only used for string literals. This means
|
|
// the lexeme isn't really the source text but
|
|
// that's not a problem for now or the forseeable
|
|
// future.
|
|
m_LexemeChar--;
|
|
for (;;)
|
|
{
|
|
AddLexeme(GetStringChar(&Escaped));
|
|
if (!Escaped &&
|
|
(*(m_LexemeChar - 1) == 0 || *(m_LexemeChar - 1) == '\"'))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
*(m_LexemeChar - 1) = 0;
|
|
|
|
m_AllowUnaryOp = FALSE;
|
|
return Wide ? CppTokenWcharString : CppTokenCharString;
|
|
}
|
|
|
|
/* Character literals */
|
|
if (Ch == '\'' ||
|
|
(Ch == 'L' && Nch == '\''))
|
|
{
|
|
BOOL Wide = FALSE;
|
|
|
|
if (Ch == 'L')
|
|
{
|
|
AddLexeme(Nch);
|
|
m_Lex++;
|
|
Wide = TRUE;
|
|
}
|
|
|
|
int Chars = 0;
|
|
ZeroMemory(&m_TokenValue, sizeof(m_TokenValue));
|
|
|
|
for (;;)
|
|
{
|
|
Ch = GetStringChar(&Escaped);
|
|
AddLexeme(Ch);
|
|
if (!Escaped && Ch == '\'')
|
|
{
|
|
if (Chars == 0)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (++Chars > 8)
|
|
{
|
|
EvalError(OVERFLOW);
|
|
}
|
|
|
|
m_TokenValue.m_S64 = (m_TokenValue.m_S64 << 8) + Ch;
|
|
}
|
|
AddLexeme(0);
|
|
|
|
switch(Chars)
|
|
{
|
|
case 1:
|
|
if (Wide)
|
|
{
|
|
m_TokenValue.SetToNativeType(DNTYPE_WCHAR_T);
|
|
}
|
|
else
|
|
{
|
|
m_TokenValue.SetToNativeType(DNTYPE_CHAR);
|
|
}
|
|
break;
|
|
case 2:
|
|
m_TokenValue.SetToNativeType(DNTYPE_INT16);
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
m_TokenValue.SetToNativeType(DNTYPE_INT32);
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
m_TokenValue.SetToNativeType(DNTYPE_INT64);
|
|
break;
|
|
}
|
|
|
|
m_AllowUnaryOp = FALSE;
|
|
return Wide ? CppTokenWchar : CppTokenChar;
|
|
}
|
|
|
|
/* Identifiers */
|
|
if (isalpha(Ch) || Ch == '_')
|
|
{
|
|
int KwToken;
|
|
|
|
for (;;)
|
|
{
|
|
Ch = *m_Lex++;
|
|
if (!isalnum(Ch) && Ch != '_')
|
|
{
|
|
break;
|
|
}
|
|
|
|
AddLexeme(Ch);
|
|
}
|
|
|
|
m_Lex--;
|
|
AddLexeme(0);
|
|
m_AllowUnaryOp = FALSE;
|
|
|
|
for (KwToken = CPP_KEYWORD_FIRST;
|
|
KwToken <= CPP_KEYWORD_LAST;
|
|
KwToken++)
|
|
{
|
|
if (!strcmp(m_LexemeStart,
|
|
s_MultiTokens[KwToken - CPP_TOKEN_MULTI]))
|
|
{
|
|
return (CppToken)KwToken;
|
|
}
|
|
}
|
|
|
|
return CppTokenIdentifier;
|
|
}
|
|
|
|
// For some reason the compiler emits symbols with
|
|
// sections between ` and '. There only seem to be
|
|
// normal characters in between them so it's unclear
|
|
// why this is done, but allow it as a special
|
|
// form of identifier.
|
|
if (Ch == '`')
|
|
{
|
|
for (;;)
|
|
{
|
|
Ch = *m_Lex++;
|
|
if (!Ch)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
|
|
AddLexeme(Ch);
|
|
if (Ch == '\'')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
AddLexeme(0);
|
|
m_AllowUnaryOp = FALSE;
|
|
|
|
return CppTokenIdentifier;
|
|
}
|
|
|
|
/* Numeric literals */
|
|
if (isdigit(Ch))
|
|
{
|
|
m_AllowUnaryOp = FALSE;
|
|
return ReadNumber(1);
|
|
}
|
|
|
|
/* Handle .[digits] floating-point literals */
|
|
if (Ch == '.')
|
|
{
|
|
if (isdigit(Nch))
|
|
{
|
|
FinishFloat(0, 1);
|
|
m_AllowUnaryOp = FALSE;
|
|
return CppTokenFloat;
|
|
}
|
|
else
|
|
{
|
|
AddLexeme(0);
|
|
return CppTokenPeriod;
|
|
}
|
|
}
|
|
|
|
/* Unambiguous single character tokens that allow unary */
|
|
if (Single = strchr("({}[;,?~.", Ch))
|
|
{
|
|
AddLexeme(0);
|
|
return (CppToken)*Single;
|
|
}
|
|
|
|
/* Unambiguous single character tokens that disallow unary */
|
|
if (Single = strchr(")]", Ch))
|
|
{
|
|
AddLexeme(0);
|
|
m_AllowUnaryOp = FALSE;
|
|
return (CppToken)*Single;
|
|
}
|
|
|
|
/* All other characters */
|
|
Nch = *m_Lex++;
|
|
CharToken = TRUE;
|
|
switch(Ch)
|
|
{
|
|
/* Comments, / and /= */
|
|
case '/':
|
|
if (Nch == '*')
|
|
{
|
|
for (;;)
|
|
{
|
|
Ch = *m_Lex++;
|
|
CheckChar:
|
|
if (!Ch)
|
|
{
|
|
break;
|
|
}
|
|
else if (Ch == '*')
|
|
{
|
|
if ((Ch = *m_Lex++) == '/')
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
goto CheckChar;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Ch)
|
|
{
|
|
EvalErrorDesc(SYNTAX, "EOF in comment");
|
|
}
|
|
|
|
CharToken = FALSE;
|
|
}
|
|
else if (Nch == '/')
|
|
{
|
|
while ((Ch = *m_Lex++) != '\n' && !IS_EOF(Ch))
|
|
{
|
|
// Iterate.
|
|
}
|
|
|
|
if (IS_EOF(Ch))
|
|
{
|
|
// IS_EOF includes EOL so EOF is not an error,
|
|
// just back up to the EOL.
|
|
m_Lex--;
|
|
}
|
|
|
|
CharToken = FALSE;
|
|
}
|
|
else if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenDivideAssign;
|
|
}
|
|
break;
|
|
|
|
/* :, :: and ::~ */
|
|
case ':':
|
|
if (Nch == ':')
|
|
{
|
|
AddLexeme(Nch);
|
|
Tch = *m_Lex++;
|
|
if (Tch == '~')
|
|
{
|
|
AddLexeme(Tch);
|
|
AddLexeme(0);
|
|
return CppTokenDestructor;
|
|
}
|
|
AddLexeme(0);
|
|
m_Lex--;
|
|
return CppTokenNameQualifier;
|
|
}
|
|
break;
|
|
|
|
/* *, *= and dereference */
|
|
case '*':
|
|
if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenMultiplyAssign;
|
|
}
|
|
else if (UnaryOp)
|
|
{
|
|
AddLexeme(0);
|
|
m_Lex--;
|
|
return CppTokenDereference;
|
|
}
|
|
break;
|
|
|
|
/* % and %= */
|
|
case '%':
|
|
if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenModuloAssign;
|
|
}
|
|
break;
|
|
|
|
/* = and == */
|
|
case '=':
|
|
if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenEqual;
|
|
}
|
|
break;
|
|
|
|
/* ! and != */
|
|
case '!':
|
|
if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenNotEqual;
|
|
}
|
|
break;
|
|
|
|
/* <, <<, <<= and <= */
|
|
case '<':
|
|
if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenLessEqual;
|
|
}
|
|
else if (Nch == '<')
|
|
{
|
|
AddLexeme(Nch);
|
|
Tch = *m_Lex++;
|
|
if (Tch == '=')
|
|
{
|
|
AddLexeme(Tch);
|
|
AddLexeme(0);
|
|
return CppTokenLeftShiftAssign;
|
|
}
|
|
AddLexeme(0);
|
|
m_Lex--;
|
|
return CppTokenLeftShift;
|
|
}
|
|
break;
|
|
|
|
/* >, >>, >>= and >= */
|
|
case '>':
|
|
if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenGreaterEqual;
|
|
}
|
|
else if (Nch == '>')
|
|
{
|
|
AddLexeme(Nch);
|
|
Tch = *m_Lex++;
|
|
if (Tch == '=')
|
|
{
|
|
AddLexeme(Tch);
|
|
AddLexeme(0);
|
|
return CppTokenRightShiftAssign;
|
|
}
|
|
AddLexeme(0);
|
|
m_Lex--;
|
|
return CppTokenRightShift;
|
|
}
|
|
break;
|
|
|
|
/* &, &= and && */
|
|
case '&':
|
|
if (Nch == '&')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenLogicalAnd;
|
|
}
|
|
else if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenAndAssign;
|
|
}
|
|
else if (UnaryOp)
|
|
{
|
|
AddLexeme(0);
|
|
m_Lex--;
|
|
return CppTokenAddressOf;
|
|
}
|
|
break;
|
|
|
|
/* |, |= and || */
|
|
case '|':
|
|
if (Nch == '|')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenLogicalOr;
|
|
}
|
|
else if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenOrAssign;
|
|
}
|
|
break;
|
|
|
|
/* ^ and ^= */
|
|
case '^':
|
|
if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenExclusiveOrAssign;
|
|
}
|
|
break;
|
|
|
|
/* U+, +, ++X, X++ and += */
|
|
case '+':
|
|
if (Nch == '+')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
if (UnaryOp)
|
|
{
|
|
return CppTokenPreIncrement;
|
|
}
|
|
else
|
|
{
|
|
m_AllowUnaryOp = FALSE;
|
|
return CppTokenPostIncrement;
|
|
}
|
|
}
|
|
else if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenAddAssign;
|
|
}
|
|
else if (UnaryOp)
|
|
{
|
|
if (isdigit(Nch))
|
|
{
|
|
AddLexeme(Nch);
|
|
m_AllowUnaryOp = FALSE;
|
|
return ReadNumber(1);
|
|
}
|
|
else
|
|
{
|
|
AddLexeme(0);
|
|
m_Lex--;
|
|
return CppTokenUnaryPlus;
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* U-, -, --, -> and -= */
|
|
case '-':
|
|
if (Nch == '-')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
if (UnaryOp)
|
|
{
|
|
return CppTokenPreDecrement;
|
|
}
|
|
else
|
|
{
|
|
m_AllowUnaryOp = FALSE;
|
|
return CppTokenPostDecrement;
|
|
}
|
|
}
|
|
else if (Nch == '=')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenSubtractAssign;
|
|
}
|
|
else if (Nch == '>')
|
|
{
|
|
AddLexeme(Nch);
|
|
AddLexeme(0);
|
|
return CppTokenPointerMember;
|
|
}
|
|
else if (UnaryOp)
|
|
{
|
|
if (isdigit(Nch))
|
|
{
|
|
AddLexeme(Nch);
|
|
m_AllowUnaryOp = FALSE;
|
|
return ReadNumber(-1);
|
|
}
|
|
else
|
|
{
|
|
AddLexeme(0);
|
|
m_Lex--;
|
|
return CppTokenUnaryMinus;
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* Special character prefix for debugger registers
|
|
and alternate evaluator expressions */
|
|
case '@':
|
|
if (Nch == '@')
|
|
{
|
|
ULONG Parens = 1;
|
|
PSTR Name;
|
|
|
|
AddLexeme(Nch);
|
|
|
|
//
|
|
// Look for an optional evaluator name.
|
|
//
|
|
|
|
Name = m_LexemeChar;
|
|
while (*m_Lex != '(' && *m_Lex != ';' && *m_Lex)
|
|
{
|
|
AddLexeme(*m_Lex++);
|
|
}
|
|
if (Name != m_LexemeChar)
|
|
{
|
|
EvalExpression* Eval;
|
|
|
|
// Name was given, identify the evaluator
|
|
// and remember the evaluator syntax.
|
|
AddLexeme(0);
|
|
GetEvaluatorByName(Name, FALSE, &Eval);
|
|
m_SwitchEvalSyntax = Eval->m_Syntax;
|
|
ReleaseEvaluator(Eval);
|
|
|
|
// Back up to overwrite the terminator.
|
|
m_LexemeChar--;
|
|
}
|
|
else
|
|
{
|
|
// No name given, default to MASM.
|
|
m_SwitchEvalSyntax = DEBUG_EXPR_MASM;
|
|
}
|
|
|
|
AddLexeme('(');
|
|
m_Lex++;
|
|
|
|
// Collect expression text to a balanced paren.
|
|
for (;;)
|
|
{
|
|
if (!*m_Lex)
|
|
{
|
|
EvalErrorDesc(SYNTAX,
|
|
"EOF in alternate evaluator expression");
|
|
}
|
|
else if (*m_Lex == '(')
|
|
{
|
|
Parens++;
|
|
}
|
|
else if (*m_Lex == ')' && --Parens == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
AddLexeme(*m_Lex++);
|
|
}
|
|
|
|
m_Lex++;
|
|
AddLexeme(')');
|
|
AddLexeme(0);
|
|
m_AllowUnaryOp = FALSE;
|
|
return CppTokenSwitchEvalExpression;
|
|
}
|
|
else
|
|
{
|
|
if (Nch == '!')
|
|
{
|
|
AddLexeme(Nch);
|
|
Nch = *m_Lex++;
|
|
}
|
|
|
|
while (isalnum(Nch) || Nch == '_' || Nch == '$')
|
|
{
|
|
AddLexeme(Nch);
|
|
Nch = *m_Lex++;
|
|
}
|
|
AddLexeme(0);
|
|
m_Lex--;
|
|
m_AllowUnaryOp = FALSE;
|
|
return m_LexemeStart[1] == '!' ?
|
|
CppTokenModule : CppTokenDebugRegister;
|
|
}
|
|
|
|
/* Special character prefix for built-in
|
|
equivalents to common preprocessor macros */
|
|
case '#':
|
|
m_Lex--;
|
|
while (isalnum(*m_Lex) || *m_Lex == '_')
|
|
{
|
|
AddLexeme(*m_Lex++);
|
|
}
|
|
AddLexeme(0);
|
|
m_AllowUnaryOp = FALSE;
|
|
return CppTokenPreprocFunction;
|
|
|
|
default:
|
|
m_Lex--;
|
|
EvalErrorDesc(SYNTAX, "Unexpected character in");
|
|
CharToken = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (CharToken)
|
|
{
|
|
m_Lex--;
|
|
AddLexeme(0);
|
|
return (CppToken)Ch;
|
|
}
|
|
}
|
|
|
|
DBG_ASSERT(!"Abnormal exit in CppLex");
|
|
return CppTokenError;
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::NextToken(void)
|
|
{
|
|
m_Token = Lex();
|
|
|
|
#if DBG_TOKENS
|
|
dprintf("Token is %s (%s)\n", TokenImage(m_Token), m_LexemeStart);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Match(CppToken Token)
|
|
{
|
|
if (m_Token != Token)
|
|
{
|
|
EvalErrorDesc(SYNTAX, "Unexpected token");
|
|
}
|
|
|
|
NextToken();
|
|
}
|
|
|
|
PCSTR
|
|
CppEvalExpression::Evaluate(PCSTR Expr, PCSTR Desc, ULONG Flags,
|
|
TypedData* Result)
|
|
{
|
|
Start(Expr, Desc, Flags);
|
|
NextToken();
|
|
|
|
if (m_Flags & EXPRF_SINGLE_TERM)
|
|
{
|
|
Match(CppTokenOpenBracket);
|
|
Expression(Result);
|
|
Match(CppTokenCloseBracket);
|
|
}
|
|
else
|
|
{
|
|
Expression(Result);
|
|
}
|
|
|
|
End(Result);
|
|
|
|
return m_LexemeSourceStart;
|
|
}
|
|
|
|
PCSTR
|
|
CppEvalExpression::EvaluateAddr(PCSTR Expr, PCSTR Desc,
|
|
ULONG SegReg, PADDR Addr)
|
|
{
|
|
// This result must be on the stack so it
|
|
// isn't caught by the empty-allocator check in end.
|
|
TypedData Result;
|
|
|
|
Start(Expr, Desc, EXPRF_DEFAULT);
|
|
NextToken();
|
|
Expression(&Result);
|
|
End(&Result);
|
|
|
|
EvalCheck(Result.ConvertToU64());
|
|
ADDRFLAT(Addr, Result.m_U64);
|
|
|
|
return m_LexemeSourceStart;
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Expression(TypedData* Result)
|
|
{
|
|
for (;;)
|
|
{
|
|
Assignment(Result);
|
|
|
|
if (m_Token == CppTokenComma)
|
|
{
|
|
Accept();
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Assignment(TypedData* Result)
|
|
{
|
|
TypedDataOp Op;
|
|
|
|
Conditional(Result);
|
|
|
|
switch(m_Token)
|
|
{
|
|
case '=':
|
|
Op = TDOP_ASSIGN;
|
|
break;
|
|
case CppTokenDivideAssign:
|
|
Op = TDOP_DIVIDE;
|
|
break;
|
|
case CppTokenMultiplyAssign:
|
|
Op = TDOP_MULTIPLY;
|
|
break;
|
|
case CppTokenModuloAssign:
|
|
Op = TDOP_REMAINDER;
|
|
break;
|
|
case CppTokenAddAssign:
|
|
Op = TDOP_ADD;
|
|
break;
|
|
case CppTokenSubtractAssign:
|
|
Op = TDOP_SUBTRACT;
|
|
break;
|
|
case CppTokenLeftShiftAssign:
|
|
Op = TDOP_LEFT_SHIFT;
|
|
break;
|
|
case CppTokenRightShiftAssign:
|
|
Op = TDOP_RIGHT_SHIFT;
|
|
break;
|
|
case CppTokenAndAssign:
|
|
Op = TDOP_BIT_AND;
|
|
break;
|
|
case CppTokenOrAssign:
|
|
Op = TDOP_BIT_OR;
|
|
break;
|
|
case CppTokenExclusiveOrAssign:
|
|
Op = TDOP_BIT_XOR;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (!Result->IsWritable())
|
|
{
|
|
EvalError(TYPECONFLICT);
|
|
}
|
|
|
|
Accept();
|
|
|
|
TypedData* Next = NewResult();
|
|
Assignment(Next);
|
|
|
|
switch(Op)
|
|
{
|
|
case TDOP_ASSIGN:
|
|
m_Tmp = *Next;
|
|
EvalCheck(m_Tmp.ConvertToSource(Result));
|
|
break;
|
|
case TDOP_ADD:
|
|
case TDOP_SUBTRACT:
|
|
case TDOP_MULTIPLY:
|
|
case TDOP_DIVIDE:
|
|
case TDOP_REMAINDER:
|
|
// Carry out the operation in a temporary as the
|
|
// address will be wiped out by the operation.
|
|
m_Tmp = *Result;
|
|
EvalCheck(m_Tmp.BinaryArithmetic(Next, Op));
|
|
// The result may be of a different type due
|
|
// to promotions or other implicit conversions.
|
|
// Force conversion to the actual result type.
|
|
EvalCheck(m_Tmp.ConvertTo(Result));
|
|
break;
|
|
case TDOP_LEFT_SHIFT:
|
|
case TDOP_RIGHT_SHIFT:
|
|
m_Tmp = *Result;
|
|
EvalCheck(m_Tmp.Shift(Next, Op));
|
|
EvalCheck(m_Tmp.ConvertTo(Result));
|
|
break;
|
|
case TDOP_BIT_OR:
|
|
case TDOP_BIT_XOR:
|
|
case TDOP_BIT_AND:
|
|
m_Tmp = *Result;
|
|
EvalCheck(m_Tmp.BinaryBitwise(Next, Op));
|
|
EvalCheck(m_Tmp.ConvertTo(Result));
|
|
break;
|
|
}
|
|
|
|
// Source and destination types should be compatible
|
|
// at this point to copy the data.
|
|
EvalCheck(Result->WriteData(&m_Tmp, CurrentAccess()));
|
|
Result->CopyData(&m_Tmp);
|
|
|
|
DelResult(Next);
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Conditional(TypedData* Result)
|
|
{
|
|
TypedData* Discard;
|
|
TypedData* Left, *Right;
|
|
|
|
LogicalOr(Result);
|
|
if (m_Token != CppTokenQuestionMark)
|
|
{
|
|
return;
|
|
}
|
|
|
|
EvalCheck(Result->ConvertToBool());
|
|
Accept();
|
|
|
|
Discard = NewResult();
|
|
if (Result->m_Bool)
|
|
{
|
|
Left = Result;
|
|
Right = Discard;
|
|
}
|
|
else
|
|
{
|
|
Left = Discard;
|
|
Right = Result;
|
|
m_ParseOnly++;
|
|
}
|
|
|
|
Expression(Left);
|
|
Match(CppTokenColon);
|
|
|
|
if (Right == Discard)
|
|
{
|
|
m_ParseOnly++;
|
|
}
|
|
else
|
|
{
|
|
m_ParseOnly--;
|
|
}
|
|
|
|
Conditional(Right);
|
|
|
|
if (Right == Discard)
|
|
{
|
|
m_ParseOnly--;
|
|
}
|
|
|
|
DelResult(Discard);
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::LogicalOr(TypedData* Result)
|
|
{
|
|
LogicalAnd(Result);
|
|
for (;;)
|
|
{
|
|
TypedData* Next;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case CppTokenLogicalOr:
|
|
EvalCheck(Result->ConvertToBool());
|
|
Accept();
|
|
if (Result->m_Bool)
|
|
{
|
|
m_ParseOnly++;
|
|
}
|
|
Next = NewResult();
|
|
LogicalAnd(Next);
|
|
EvalCheck(Next->ConvertToBool());
|
|
if (Result->m_Bool)
|
|
{
|
|
m_ParseOnly--;
|
|
}
|
|
else
|
|
{
|
|
Result->m_Bool = Result->m_Bool || Next->m_Bool;
|
|
}
|
|
DelResult(Next);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::LogicalAnd(TypedData* Result)
|
|
{
|
|
BitwiseOr(Result);
|
|
for (;;)
|
|
{
|
|
TypedData* Next;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case CppTokenLogicalAnd:
|
|
EvalCheck(Result->ConvertToBool());
|
|
Accept();
|
|
if (!Result->m_Bool)
|
|
{
|
|
m_ParseOnly++;
|
|
}
|
|
Next = NewResult();
|
|
BitwiseOr(Next);
|
|
EvalCheck(Next->ConvertToBool());
|
|
if (!Result->m_Bool)
|
|
{
|
|
m_ParseOnly--;
|
|
}
|
|
else
|
|
{
|
|
Result->m_Bool = Result->m_Bool && Next->m_Bool;
|
|
}
|
|
DelResult(Next);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::BitwiseOr(TypedData* Result)
|
|
{
|
|
BitwiseXor(Result);
|
|
for (;;)
|
|
{
|
|
TypedData* Next;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case '|':
|
|
Accept();
|
|
Next = NewResult();
|
|
BitwiseXor(Next);
|
|
EvalCheck(Result->BinaryBitwise(Next, TDOP_BIT_OR));
|
|
DelResult(Next);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::BitwiseXor(TypedData* Result)
|
|
{
|
|
BitwiseAnd(Result);
|
|
for (;;)
|
|
{
|
|
TypedData* Next;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case '^':
|
|
Accept();
|
|
Next = NewResult();
|
|
BitwiseAnd(Next);
|
|
EvalCheck(Result->BinaryBitwise(Next, TDOP_BIT_XOR));
|
|
DelResult(Next);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::BitwiseAnd(TypedData* Result)
|
|
{
|
|
Equality(Result);
|
|
for (;;)
|
|
{
|
|
TypedData* Next;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case '&':
|
|
Accept();
|
|
Next = NewResult();
|
|
Equality(Next);
|
|
EvalCheck(Result->BinaryBitwise(Next, TDOP_BIT_AND));
|
|
DelResult(Next);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Equality(TypedData* Result)
|
|
{
|
|
Relational(Result);
|
|
for (;;)
|
|
{
|
|
TypedDataOp Op;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case CppTokenEqual:
|
|
Op = TDOP_EQUAL;
|
|
break;
|
|
case CppTokenNotEqual:
|
|
Op = TDOP_NOT_EQUAL;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
Accept();
|
|
|
|
TypedData* Next = NewResult();
|
|
Relational(Next);
|
|
EvalCheck(Result->Relate(Next, Op));
|
|
DelResult(Next);
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Relational(TypedData* Result)
|
|
{
|
|
Shift(Result);
|
|
for (;;)
|
|
{
|
|
TypedDataOp Op;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case '<':
|
|
Op = TDOP_LESS;
|
|
break;
|
|
case '>':
|
|
Op = TDOP_GREATER;
|
|
break;
|
|
case CppTokenLessEqual:
|
|
Op = TDOP_LESS_EQUAL;
|
|
break;
|
|
case CppTokenGreaterEqual:
|
|
Op = TDOP_GREATER_EQUAL;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
Accept();
|
|
|
|
TypedData* Next = NewResult();
|
|
Shift(Next);
|
|
EvalCheck(Result->Relate(Next, Op));
|
|
DelResult(Next);
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Shift(TypedData* Result)
|
|
{
|
|
Additive(Result);
|
|
for (;;)
|
|
{
|
|
TypedDataOp Op;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case CppTokenLeftShift:
|
|
Op = TDOP_LEFT_SHIFT;
|
|
break;
|
|
case CppTokenRightShift:
|
|
Op = TDOP_RIGHT_SHIFT;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
Accept();
|
|
|
|
TypedData* Next = NewResult();
|
|
Additive(Next);
|
|
EvalCheck(Result->Shift(Next, Op));
|
|
DelResult(Next);
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Additive(TypedData* Result)
|
|
{
|
|
Multiplicative(Result);
|
|
for (;;)
|
|
{
|
|
TypedDataOp Op;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case '+':
|
|
Op = TDOP_ADD;
|
|
break;
|
|
case '-':
|
|
Op = TDOP_SUBTRACT;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
Accept();
|
|
|
|
TypedData* Next = NewResult();
|
|
Multiplicative(Next);
|
|
EvalCheck(Result->BinaryArithmetic(Next, Op));
|
|
DelResult(Next);
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Multiplicative(TypedData* Result)
|
|
{
|
|
ClassMemberRef(Result);
|
|
for (;;)
|
|
{
|
|
TypedDataOp Op;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case '*':
|
|
Op = TDOP_MULTIPLY;
|
|
break;
|
|
case '/':
|
|
Op = TDOP_DIVIDE;
|
|
break;
|
|
case '%':
|
|
Op = TDOP_REMAINDER;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
Accept();
|
|
|
|
TypedData* Next = NewResult();
|
|
ClassMemberRef(Next);
|
|
EvalCheck(Result->BinaryArithmetic(Next, Op));
|
|
DelResult(Next);
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::ClassMemberRef(TypedData* Result)
|
|
{
|
|
Cast(Result);
|
|
for (;;)
|
|
{
|
|
//
|
|
// Calling through pointers to members isn't
|
|
// supported, just as normal function calls
|
|
// aren't supported. We could potentially
|
|
// determine the actual method value for
|
|
// simple references to methods but there's
|
|
// virtual no need for that, so just fail
|
|
// these constructs.
|
|
//
|
|
|
|
switch(m_Token)
|
|
{
|
|
case CppTokenClassDereference:
|
|
case CppTokenClassPointerMember:
|
|
EvalErrorDesc(UNIMPLEMENT,
|
|
"Pointer to member evaluation is not supported");
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Cast(TypedData* Result)
|
|
{
|
|
if (m_Token == '(')
|
|
{
|
|
PCSTR LexRestart = m_Lex;
|
|
|
|
Accept();
|
|
if (TryTypeName(Result) == ERES_TYPE)
|
|
{
|
|
//
|
|
// It was a type name, so process the cast.
|
|
//
|
|
|
|
TypedData* CastType = NewResult();
|
|
*CastType = *Result;
|
|
// Unary is allowed after a cast.
|
|
m_AllowUnaryOp = TRUE;
|
|
Match(CppTokenCloseParen);
|
|
Cast(Result);
|
|
EvalCheck(Result->CastTo(CastType));
|
|
DelResult(CastType);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// It wasn't a type, so restart the lexer
|
|
// and reparse as an expression.
|
|
StartLexer(LexRestart);
|
|
strcpy(m_LexemeStart, "(");
|
|
m_Token = CppTokenOpenParen;
|
|
}
|
|
}
|
|
|
|
Unary(Result);
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Unary(TypedData* Result)
|
|
{
|
|
CppToken Op = m_Token;
|
|
switch(Op)
|
|
{
|
|
case CppTokenSizeof:
|
|
Accept();
|
|
if (m_Token == '(')
|
|
{
|
|
PCSTR LexRestart = m_Lex;
|
|
Accept();
|
|
if (TryTypeName(Result) == ERES_TYPE)
|
|
{
|
|
// It was a type name.
|
|
Match(CppTokenCloseParen);
|
|
}
|
|
else
|
|
{
|
|
// It wasn't a type, so restart the lexer
|
|
// and reparse as an expression.
|
|
StartLexer(LexRestart);
|
|
strcpy(m_LexemeStart, "(");
|
|
m_Token = CppTokenOpenParen;
|
|
Unary(Result);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Unary(Result);
|
|
}
|
|
Result->m_U64 = Result->m_BaseSize;
|
|
Result->SetToNativeType(m_PtrSize == sizeof(ULONG64) ?
|
|
DNTYPE_UINT64 : DNTYPE_UINT32);
|
|
break;
|
|
case CppTokenUnaryPlus:
|
|
case CppTokenUnaryMinus:
|
|
case '~':
|
|
Accept();
|
|
Cast(Result);
|
|
if (Op == CppTokenUnaryPlus)
|
|
{
|
|
// Nothing to do.
|
|
break;
|
|
}
|
|
EvalCheck(Result->Unary(Op == CppTokenUnaryMinus ?
|
|
TDOP_NEGATE : TDOP_BIT_NOT));
|
|
break;
|
|
case '!':
|
|
Accept();
|
|
Cast(Result);
|
|
EvalCheck(Result->ConvertToBool());
|
|
Result->m_Bool = !Result->m_Bool;
|
|
break;
|
|
case CppTokenAddressOf:
|
|
Accept();
|
|
Cast(Result);
|
|
if (!Result->HasAddress())
|
|
{
|
|
EvalErrorDesc(SYNTAX, "No address for operator&");
|
|
}
|
|
EvalCheck(Result->ConvertToAddressOf(FALSE, m_PtrSize));
|
|
#if DBG_TYPES
|
|
dprintf("& -> id %s!%x, base %x, size %x\n",
|
|
Result->m_Image ? Result->m_Image->m_ModuleName : "<>",
|
|
Result->m_Type, Result->m_BaseType, Result->m_BaseSize);
|
|
#endif
|
|
break;
|
|
case CppTokenDereference:
|
|
Accept();
|
|
Cast(Result);
|
|
if (!Result->IsPointer())
|
|
{
|
|
EvalErrorDesc(SYNTAX, "No pointer for operator*");
|
|
}
|
|
EvalCheck(Result->ConvertToDereference(CurrentAccess(), m_PtrSize));
|
|
#if DBG_TYPES
|
|
dprintf("* -> id %s!%x, base %x, size %x\n",
|
|
Result->m_Image ? Result->m_Image->m_ModuleName : "<>",
|
|
Result->m_Type, Result->m_BaseType, Result->m_BaseSize);
|
|
#endif
|
|
break;
|
|
case CppTokenPreIncrement:
|
|
case CppTokenPreDecrement:
|
|
Accept();
|
|
Unary(Result);
|
|
if (!Result->IsInteger() && !Result->IsPointer())
|
|
{
|
|
EvalError(TYPECONFLICT);
|
|
}
|
|
// Carry out the operation in a temporary as the
|
|
// address will be wiped out by the operation.
|
|
m_Tmp = *Result;
|
|
if ((m_Err = m_Tmp.ConstIntOp(Op == CppTokenPreIncrement ? 1 : -1,
|
|
TRUE, TDOP_ADD)) ||
|
|
(m_Err = Result->WriteData(&m_Tmp, CurrentAccess())))
|
|
{
|
|
EvalError(m_Err);
|
|
}
|
|
Result->CopyData(&m_Tmp);
|
|
break;
|
|
default:
|
|
Postfix(Result);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Postfix(TypedData* Result)
|
|
{
|
|
TypedData* Next;
|
|
|
|
if (m_Token == CppTokenDynamicCast ||
|
|
m_Token == CppTokenStaticCast ||
|
|
m_Token == CppTokenConstCast ||
|
|
m_Token == CppTokenReinterpretCast)
|
|
{
|
|
// Don't bother trying to emulate
|
|
// the precise rules on casting for
|
|
// these operators, just cast.
|
|
Accept();
|
|
Match(CppTokenOpenAngle);
|
|
Next = NewResult();
|
|
if (TryTypeName(Next) != ERES_TYPE)
|
|
{
|
|
EvalError(TYPECONFLICT);
|
|
}
|
|
Match(CppTokenCloseAngle);
|
|
Match(CppTokenOpenParen);
|
|
Expression(Result);
|
|
Match(CppTokenCloseParen);
|
|
EvalCheck(Result->CastTo(Next));
|
|
DelResult(Next);
|
|
return;
|
|
}
|
|
|
|
Term(Result);
|
|
for (;;)
|
|
{
|
|
CppToken Op = m_Token;
|
|
switch(Op)
|
|
{
|
|
case '.':
|
|
if (!Result->IsUdt())
|
|
{
|
|
EvalErrorDesc(TYPECONFLICT,
|
|
"Type is not struct/class/union for operator.");
|
|
}
|
|
Accept();
|
|
UdtMember(Result);
|
|
break;
|
|
case CppTokenPointerMember:
|
|
if (!Result->IsPointer())
|
|
{
|
|
EvalErrorDesc(TYPECONFLICT,
|
|
"Type is not pointer for operator->");
|
|
}
|
|
Accept();
|
|
UdtMember(Result);
|
|
break;
|
|
case '[':
|
|
if (Result->IsArray())
|
|
{
|
|
// There's no need to do a full address convert
|
|
// as all we're going to do is deref later.
|
|
EvalCheck(Result->GetAbsoluteAddress(&Result->m_Ptr));
|
|
}
|
|
else if (!Result->IsPointer())
|
|
{
|
|
EvalErrorDesc(TYPECONFLICT,
|
|
"Type is not a pointer for operator[]");
|
|
}
|
|
if (!Result->m_NextSize)
|
|
{
|
|
EvalError(TYPECONFLICT);
|
|
}
|
|
Accept();
|
|
Next = NewResult();
|
|
Expression(Next);
|
|
if (!Next->IsInteger())
|
|
{
|
|
EvalErrorDesc(TYPECONFLICT,
|
|
"Array index not integral");
|
|
}
|
|
EvalCheck(Next->ConvertToU64());
|
|
Result->m_Ptr += Next->m_U64 * Result->m_NextSize;
|
|
DelResult(Next);
|
|
EvalCheck(Result->
|
|
ConvertToDereference(CurrentAccess(), m_PtrSize));
|
|
Match(CppTokenCloseBracket);
|
|
break;
|
|
case CppTokenPostIncrement:
|
|
case CppTokenPostDecrement:
|
|
if (!Result->IsInteger() && !Result->IsPointer())
|
|
{
|
|
EvalError(TYPECONFLICT);
|
|
}
|
|
m_Tmp = *Result;
|
|
if ((m_Err = m_Tmp.ConstIntOp(Op == CppTokenPostIncrement ? 1 : -1,
|
|
TRUE, TDOP_ADD)) ||
|
|
(m_Err = Result->WriteData(&m_Tmp, CurrentAccess())))
|
|
{
|
|
EvalError(m_Err);
|
|
}
|
|
Accept();
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::Term(TypedData* Result)
|
|
{
|
|
EVAL_RESULT_KIND IdKind;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case CppTokenInteger:
|
|
case CppTokenFloat:
|
|
case CppTokenWchar:
|
|
case CppTokenChar:
|
|
*Result = m_TokenValue;
|
|
#if DBG_TYPES
|
|
dprintf("%s -> id %s!%x, base %x, size %x\n",
|
|
m_LexemeStart,
|
|
Result->m_Image ? Result->m_Image->m_ModuleName : "<>",
|
|
Result->m_Type, Result->m_BaseType, Result->m_BaseSize);
|
|
#endif
|
|
Accept();
|
|
break;
|
|
|
|
case CppTokenWcharString:
|
|
case CppTokenCharString:
|
|
EvalErrorDesc(SYNTAX, "String literals not allowed in");
|
|
|
|
case CppTokenIdentifier:
|
|
IdKind = CollectTypeOrSymbolName(Result);
|
|
if (IdKind == ERES_TYPE)
|
|
{
|
|
TypedData* Type = NewResult();
|
|
*Type = *Result;
|
|
|
|
Match(CppTokenOpenParen);
|
|
Expression(Result);
|
|
Match(CppTokenCloseParen);
|
|
EvalCheck(Result->CastTo(Type));
|
|
DelResult(Type);
|
|
}
|
|
else if (IdKind == ERES_SYMBOL)
|
|
{
|
|
#if DBG_TYPES
|
|
dprintf("symbol -> id %s!%x, base %x, size %x\n",
|
|
Result->m_Image ? Result->m_Image->m_ModuleName : "<>",
|
|
Result->m_Type, Result->m_BaseType, Result->m_BaseSize);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
EvalError(VARDEF);
|
|
}
|
|
break;
|
|
|
|
case CppTokenThis:
|
|
if (!m_Process)
|
|
{
|
|
EvalError(BADPROCESS);
|
|
}
|
|
EvalCheck(Result->FindSymbol(m_Process, m_LexemeStart,
|
|
CurrentAccess(), m_PtrSize));
|
|
#if DBG_TYPES
|
|
dprintf("%s -> id %s!%x, base %x, size %x\n",
|
|
m_LexemeStart,
|
|
Result->m_Image ? Result->m_Image->m_ModuleName : "<>",
|
|
Result->m_Type, Result->m_BaseType, Result->m_BaseSize);
|
|
#endif
|
|
Accept();
|
|
break;
|
|
|
|
case '(':
|
|
Accept();
|
|
Expression(Result);
|
|
Match(CppTokenCloseParen);
|
|
break;
|
|
|
|
case CppTokenDebugRegister:
|
|
// Skip @ at the beginning.
|
|
if (!GetPsuedoOrRegTypedData(TRUE, m_LexemeStart + 1, Result))
|
|
{
|
|
if (GetOffsetFromBreakpoint(m_LexemeStart + 1, &Result->m_U64))
|
|
{
|
|
Result->SetToNativeType(DNTYPE_UINT64);
|
|
Result->ClearAddress();
|
|
}
|
|
else
|
|
{
|
|
EvalError(VARDEF);
|
|
}
|
|
}
|
|
#if DBG_TYPES
|
|
dprintf("%s -> id %s!%x, base %x, size %x\n",
|
|
m_LexemeStart,
|
|
Result->m_Image ? Result->m_Image->m_ModuleName : "<>",
|
|
Result->m_Type, Result->m_BaseType, Result->m_BaseSize);
|
|
#endif
|
|
Accept();
|
|
break;
|
|
|
|
case CppTokenModule:
|
|
// Skip the @! at the beginning.
|
|
if (g_Process->GetOffsetFromMod(m_LexemeStart + 2, &Result->m_U64))
|
|
{
|
|
Result->SetToNativeType(DNTYPE_UINT64);
|
|
Result->ClearAddress();
|
|
}
|
|
else
|
|
{
|
|
EvalError(VARDEF);
|
|
}
|
|
Accept();
|
|
break;
|
|
|
|
case CppTokenSwitchEvalExpression:
|
|
EvalExpression* Eval;
|
|
PSTR ExprStart;
|
|
|
|
Eval = GetEvaluator(m_SwitchEvalSyntax, FALSE);
|
|
Eval->InheritStart(this);
|
|
// Allow all nested evaluators to get cleaned up.
|
|
Eval->m_ChainTop = FALSE;
|
|
ExprStart = m_LexemeStart + 2;
|
|
while (*ExprStart && *ExprStart != '(')
|
|
{
|
|
ExprStart++;
|
|
}
|
|
Eval->Evaluate(ExprStart, NULL, EXPRF_DEFAULT, Result);
|
|
Eval->InheritEnd(this);
|
|
ReleaseEvaluator(Eval);
|
|
|
|
Accept();
|
|
break;
|
|
|
|
case CppTokenPreprocFunction:
|
|
PreprocFunction(Result);
|
|
break;
|
|
|
|
default:
|
|
EvalErrorDesc(SYNTAX, m_ExprDesc);
|
|
}
|
|
}
|
|
|
|
EVAL_RESULT_KIND
|
|
CppEvalExpression::TryTypeName(TypedData* Result)
|
|
{
|
|
//
|
|
// If the following tokens can be evaluated as
|
|
// a type then do so, otherwise exit.
|
|
//
|
|
|
|
if (CollectTypeOrSymbolName(Result) == ERES_TYPE)
|
|
{
|
|
BOOL Scan = TRUE;
|
|
|
|
while (Scan)
|
|
{
|
|
TypedData* Elements;
|
|
|
|
switch(m_Token)
|
|
{
|
|
case '*':
|
|
case CppTokenDereference:
|
|
EvalCheck(Result->ConvertToAddressOf(TRUE, m_PtrSize));
|
|
Accept();
|
|
break;
|
|
case '[':
|
|
Elements = NewResult();
|
|
Accept();
|
|
if (m_Token != ']')
|
|
{
|
|
Conditional(Elements);
|
|
if (!Elements->IsInteger())
|
|
{
|
|
EvalErrorDesc(SYNTAX, "Array length not integral");
|
|
}
|
|
EvalCheck(Elements->ConvertToU64());
|
|
Elements->m_U64 *= Result->m_BaseSize;
|
|
}
|
|
else
|
|
{
|
|
// For a elementless array make it the same
|
|
// size as a pointer as that's essentially.
|
|
// what it is.
|
|
Elements->m_U64 = m_PtrSize;
|
|
}
|
|
Match(CppTokenCloseBracket);
|
|
EvalCheck(Result->ConvertToArray((ULONG)Elements->m_U64));
|
|
DelResult(Elements);
|
|
break;
|
|
default:
|
|
Scan = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if DBG_TYPES
|
|
dprintf("type -> id %s!%x, base %x, size %x\n",
|
|
Result->m_Image ? Result->m_Image->m_ModuleName : "<>",
|
|
Result->m_Type, Result->m_BaseType, Result->m_BaseSize);
|
|
#endif
|
|
return ERES_TYPE;
|
|
}
|
|
else
|
|
{
|
|
// It wasn't a cast, let the caller handle it.
|
|
return ERES_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
EVAL_RESULT_KIND
|
|
CppEvalExpression::CollectTypeOrSymbolName(TypedData* Result)
|
|
{
|
|
EVAL_RESULT_KIND ResKind = ERES_UNKNOWN;
|
|
CppToken LastToken = CppTokenError;
|
|
PCSTR SourceStart = m_LexemeSourceStart;
|
|
ULONG Len;
|
|
|
|
for (;;)
|
|
{
|
|
if (IsTypeKeyword(m_Token))
|
|
{
|
|
if (!(LastToken == CppTokenError ||
|
|
LastToken == CppTokenIdentifier ||
|
|
IsTypeKeyword(LastToken)) ||
|
|
(ResKind != ERES_TYPE && ResKind != ERES_UNKNOWN))
|
|
{
|
|
break;
|
|
}
|
|
|
|
m_LexemeRestart += strlen(m_LexemeRestart);
|
|
*m_LexemeRestart++ = ' ';
|
|
*m_LexemeRestart = 0;
|
|
|
|
LastToken = m_Token;
|
|
Accept();
|
|
ResKind = ERES_TYPE;
|
|
}
|
|
else if (m_Token == CppTokenIdentifier)
|
|
{
|
|
if (LastToken == CppTokenIdentifier)
|
|
{
|
|
break;
|
|
}
|
|
|
|
m_LexemeRestart += strlen(m_LexemeRestart);
|
|
*m_LexemeRestart++ = ' ';
|
|
*m_LexemeRestart = 0;
|
|
LastToken = m_Token;
|
|
Accept();
|
|
}
|
|
else if (m_Token == CppTokenModule)
|
|
{
|
|
if (LastToken != CppTokenError)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Back up over @!.
|
|
Len = strlen(m_LexemeRestart) - 2;
|
|
memmove(m_LexemeRestart, m_LexemeRestart + 2, Len);
|
|
m_LexemeRestart += Len;
|
|
*m_LexemeRestart++ = ' ';
|
|
*m_LexemeRestart = 0;
|
|
LastToken = m_Token;
|
|
Accept();
|
|
}
|
|
else if (m_Token == CppTokenNameQualifier ||
|
|
m_Token == CppTokenDestructor)
|
|
{
|
|
if (LastToken != CppTokenIdentifier &&
|
|
LastToken != CppTokenCloseAngle)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Some kind of member reference so keep collecting.
|
|
//
|
|
|
|
// Eliminate unnecessary space after identifier.
|
|
Len = strlen(m_LexemeRestart) + 1;
|
|
memmove(m_LexemeRestart - 1, m_LexemeRestart, Len);
|
|
m_LexemeRestart += Len - 2;
|
|
LastToken = m_Token;
|
|
Accept();
|
|
}
|
|
else if (m_Token == '!')
|
|
{
|
|
if (LastToken != CppTokenIdentifier &&
|
|
LastToken != CppTokenModule)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Special syntax to allow module scoping for symbols.
|
|
//
|
|
|
|
// Eliminate unnecessary space after identifier.
|
|
*(m_LexemeRestart - 1) = (char)m_Token;
|
|
*m_LexemeRestart = 0;
|
|
LastToken = m_Token;
|
|
Accept();
|
|
}
|
|
else if (m_Token == CppTokenOpenAngle)
|
|
{
|
|
if (LastToken != CppTokenIdentifier)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (CollectTemplateName() == ERES_UNKNOWN)
|
|
{
|
|
break;
|
|
}
|
|
|
|
*++m_LexemeRestart = 0;
|
|
LastToken = m_Token;
|
|
Accept();
|
|
}
|
|
else if (m_Token == CppTokenOperator)
|
|
{
|
|
if (LastToken != CppTokenError &&
|
|
LastToken != '!' &&
|
|
LastToken != CppTokenNameQualifier)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Set LastToken first so it's CppTokenOperator for
|
|
// all operators.
|
|
LastToken = m_Token;
|
|
ResKind = ERES_SYMBOL;
|
|
|
|
CollectOperatorName();
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (LastToken == CppTokenNameQualifier ||
|
|
LastToken == CppTokenDestructor ||
|
|
LastToken == '!')
|
|
{
|
|
// Incomplete name.
|
|
m_LexemeSourceStart = SourceStart;
|
|
EvalErrorDesc(SYNTAX, "Incomplete symbol or type name");
|
|
}
|
|
|
|
if (LastToken == CppTokenModule)
|
|
{
|
|
// If the last token was a module name assume this
|
|
// is a plain module name expression.
|
|
return ERES_EXPRESSION;
|
|
}
|
|
|
|
PSTR End;
|
|
char Save;
|
|
|
|
End = m_LexemeRestart;
|
|
if (End > m_LexemeBuffer && *(End - 1) == ' ')
|
|
{
|
|
End--;
|
|
}
|
|
|
|
if (!m_Process || End == m_LexemeBuffer)
|
|
{
|
|
// Can't look anything up without a process or name.
|
|
return ERES_UNKNOWN;
|
|
}
|
|
|
|
Save = *End;
|
|
*End = 0;
|
|
|
|
// Clear the data address up front for the type cases
|
|
// with no addresses.
|
|
Result->ClearAddress();
|
|
Result->ClearData();
|
|
|
|
m_Err = VARDEF;
|
|
|
|
if (ResKind != ERES_SYMBOL)
|
|
{
|
|
// First check for a built-in type as this greatly speeds
|
|
// up references to them. This should always be legal
|
|
// because they're keywords so they can't be overriden
|
|
// by symbols.
|
|
PDBG_NATIVE_TYPE Native = FindNativeTypeByName(m_LexemeBuffer);
|
|
if (Native)
|
|
{
|
|
Result->SetToNativeType(DbgNativeTypeId(Native));
|
|
m_Err = NO_ERROR;
|
|
ResKind = ERES_TYPE;
|
|
}
|
|
}
|
|
|
|
if (m_Err && ResKind != ERES_TYPE)
|
|
{
|
|
m_Err = Result->FindSymbol(m_Process, m_LexemeBuffer,
|
|
CurrentAccess(), m_PtrSize);
|
|
if (!m_Err)
|
|
{
|
|
ResKind = ERES_SYMBOL;
|
|
}
|
|
}
|
|
|
|
if (m_Err && ResKind != ERES_SYMBOL)
|
|
{
|
|
m_Err = Result->FindType(m_Process, m_LexemeBuffer, m_PtrSize);
|
|
if (!m_Err)
|
|
{
|
|
ResKind = ERES_TYPE;
|
|
}
|
|
}
|
|
|
|
if (m_Err)
|
|
{
|
|
if (m_AllowUnresolvedSymbols)
|
|
{
|
|
// Always assume that unresolved symbols are symbols.
|
|
m_NumUnresolvedSymbols++;
|
|
ResKind = ERES_SYMBOL;
|
|
}
|
|
else
|
|
{
|
|
m_LexemeSourceStart = SourceStart;
|
|
EvalError(m_Err);
|
|
}
|
|
}
|
|
|
|
*End = Save;
|
|
m_LexemeRestart = m_LexemeBuffer;
|
|
return ResKind;
|
|
}
|
|
|
|
EVAL_RESULT_KIND
|
|
CppEvalExpression::CollectTemplateName(void)
|
|
{
|
|
EVAL_RESULT_KIND ResKind;
|
|
|
|
//
|
|
// Templates are difficult to distinguish from
|
|
// normal arithmetic expressions. Do a prefix
|
|
// search for any symbol starting with what we
|
|
// have so far and a <. If something hits, assume
|
|
// that this is a template reference and consume
|
|
// everything to a matching >.
|
|
//
|
|
|
|
if (!m_Process)
|
|
{
|
|
// Can't look up anything without a process.
|
|
return ERES_UNKNOWN;
|
|
}
|
|
|
|
// Eliminate unnecessary space after identifier.
|
|
*(m_LexemeRestart - 1) = (char)m_Token;
|
|
*m_LexemeRestart++ = '*';
|
|
*m_LexemeRestart = 0;
|
|
|
|
//
|
|
// Check for a symbol or type match.
|
|
//
|
|
|
|
SYMBOL_INFO SymInfo = {0};
|
|
|
|
if (!SymFromName(m_Process->m_SymHandle, m_LexemeBuffer, &SymInfo))
|
|
{
|
|
PSTR ModNameEnd;
|
|
ImageInfo* Mod, *ModList;
|
|
|
|
ModNameEnd = strchr(m_LexemeBuffer, '!');
|
|
if (!ModNameEnd)
|
|
{
|
|
ModNameEnd = m_LexemeBuffer;
|
|
Mod = NULL;
|
|
}
|
|
else
|
|
{
|
|
Mod = m_Process->
|
|
FindImageByName(m_LexemeBuffer,
|
|
(ULONG)(ModNameEnd - m_LexemeBuffer),
|
|
INAME_MODULE, FALSE);
|
|
if (!Mod)
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
ModNameEnd++;
|
|
}
|
|
|
|
for (ModList = m_Process->m_ImageHead;
|
|
ModList;
|
|
ModList = ModList->m_Next)
|
|
{
|
|
if (Mod && ModList != Mod)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (SymGetTypeFromName(m_Process->m_SymHandle,
|
|
ModList->m_BaseOfImage,
|
|
ModNameEnd, &SymInfo))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!ModList)
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
ResKind = ERES_TYPE;
|
|
}
|
|
else
|
|
{
|
|
ResKind = ERES_SYMBOL;
|
|
}
|
|
|
|
//
|
|
// Collect everything until a matching >.
|
|
//
|
|
|
|
ULONG Nest = 1;
|
|
|
|
*--m_LexemeRestart = 0;
|
|
|
|
for (;;)
|
|
{
|
|
Accept();
|
|
|
|
if (m_Token == CppTokenEof)
|
|
{
|
|
EvalErrorDesc(SYNTAX, "EOF in template");
|
|
}
|
|
|
|
// Put a space after commas and pack everything else.
|
|
m_LexemeRestart += strlen(m_LexemeRestart);
|
|
if (m_Token == CppTokenCloseAngle && --Nest == 0)
|
|
{
|
|
break;
|
|
}
|
|
else if (m_Token == CppTokenOpenAngle)
|
|
{
|
|
Nest++;
|
|
}
|
|
else if (m_Token == ',')
|
|
{
|
|
*m_LexemeRestart++ = ' ';
|
|
*m_LexemeRestart = 0;
|
|
}
|
|
}
|
|
|
|
return ResKind;
|
|
|
|
Error:
|
|
// No match.
|
|
m_LexemeRestart -= 2;
|
|
*m_LexemeRestart++ = ' ';
|
|
*m_LexemeRestart = 0;
|
|
return ERES_UNKNOWN;
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::CollectOperatorName(void)
|
|
{
|
|
PSTR OpEnd;
|
|
|
|
//
|
|
// Add in "operator".
|
|
//
|
|
|
|
m_LexemeRestart += strlen(m_LexemeRestart);
|
|
OpEnd = m_LexemeRestart;
|
|
Accept();
|
|
|
|
//
|
|
// Immediately process the specific operator tokens.
|
|
//
|
|
|
|
if (m_Token == CppTokenNew || m_Token == CppTokenDelete)
|
|
{
|
|
ULONG Len;
|
|
|
|
// Put a space before new/delete.
|
|
Len = strlen(OpEnd) + 1;
|
|
memmove(OpEnd + 1, OpEnd, Len);
|
|
*OpEnd = ' ';
|
|
|
|
m_LexemeRestart = OpEnd + Len;
|
|
Accept();
|
|
|
|
// Check for vector forms.
|
|
if (m_Token == CppTokenOpenBracket)
|
|
{
|
|
m_LexemeRestart += strlen(m_LexemeRestart);
|
|
Accept();
|
|
if (m_Token != CppTokenCloseBracket)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
m_LexemeRestart += strlen(m_LexemeRestart);
|
|
Accept();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(m_Token)
|
|
{
|
|
case '+':
|
|
case '-':
|
|
case '*':
|
|
case '/':
|
|
case '%':
|
|
case '^':
|
|
case '&':
|
|
case '|':
|
|
case '~':
|
|
case '!':
|
|
case '=':
|
|
case '<':
|
|
case '>':
|
|
case ',':
|
|
case CppTokenEqual:
|
|
case CppTokenNotEqual:
|
|
case CppTokenLessEqual:
|
|
case CppTokenGreaterEqual:
|
|
case CppTokenLogicalAnd:
|
|
case CppTokenLogicalOr:
|
|
case CppTokenUnaryPlus:
|
|
case CppTokenUnaryMinus:
|
|
case CppTokenLeftShift:
|
|
case CppTokenRightShift:
|
|
case CppTokenAddressOf:
|
|
case CppTokenDereference:
|
|
case CppTokenPointerMember:
|
|
case CppTokenClassDereference:
|
|
case CppTokenClassPointerMember:
|
|
case CppTokenDivideAssign:
|
|
case CppTokenMultiplyAssign:
|
|
case CppTokenModuloAssign:
|
|
case CppTokenAddAssign:
|
|
case CppTokenSubtractAssign:
|
|
case CppTokenLeftShiftAssign:
|
|
case CppTokenRightShiftAssign:
|
|
case CppTokenAndAssign:
|
|
case CppTokenOrAssign:
|
|
case CppTokenExclusiveOrAssign:
|
|
case CppTokenPreIncrement:
|
|
case CppTokenPreDecrement:
|
|
case CppTokenPostIncrement:
|
|
case CppTokenPostDecrement:
|
|
break;
|
|
case '(':
|
|
m_LexemeRestart += strlen(m_LexemeRestart);
|
|
Accept();
|
|
if (m_Token != CppTokenCloseParen)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
break;
|
|
case '[':
|
|
m_LexemeRestart += strlen(m_LexemeRestart);
|
|
Accept();
|
|
if (m_Token != CppTokenCloseBracket)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
break;
|
|
default:
|
|
// Unrecognized operator.
|
|
EvalError(SYNTAX);
|
|
}
|
|
|
|
m_LexemeRestart += strlen(m_LexemeRestart);
|
|
Accept();
|
|
}
|
|
}
|
|
|
|
void
|
|
CppEvalExpression::UdtMember(TypedData* Result)
|
|
{
|
|
if (m_Token != CppTokenIdentifier)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
|
|
EvalCheck(Result->ConvertToMember(m_LexemeStart, CurrentAccess(),
|
|
m_PtrSize));
|
|
#if DBG_TYPES
|
|
dprintf("%s -> id %s!%x, base %x, size %x\n",
|
|
m_LexemeStart,
|
|
Result->m_Image ? Result->m_Image->m_ModuleName : "<>",
|
|
Result->m_Type, Result->m_BaseType, Result->m_BaseSize);
|
|
#endif
|
|
Accept();
|
|
}
|
|
|
|
#define MAX_CPP_ARGS 16
|
|
|
|
struct CPP_REPLACEMENT
|
|
{
|
|
PSTR Name;
|
|
ULONG NumArgs;
|
|
PSTR Repl;
|
|
};
|
|
|
|
CPP_REPLACEMENT g_CppPreProcFn[] =
|
|
{
|
|
"CONTAINING_RECORD", 3,
|
|
"(($1$ *)((char*)($0$) - (int64)(&(($1$ *)0)->$2$)))",
|
|
"FIELD_OFFSET", 2,
|
|
"((long)&((($0$ *)0)->$1$))",
|
|
"RTL_FIELD_SIZE", 2,
|
|
"(sizeof((($0$ *)0)->$1$))",
|
|
"RTL_SIZEOF_THROUGH_FIELD", 2,
|
|
"(#FIELD_OFFSET($0$, $1$) + #RTL_FIELD_SIZE($0$, $1$))",
|
|
"RTL_CONTAINS_FIELD", 3,
|
|
"((((char*)(&($0$)->$2$)) + sizeof(($0$)->$2$)) <= "
|
|
"((char*)($0$))+($1$)))",
|
|
"RTL_NUMBER_OF", 1,
|
|
"(sizeof($0$)/sizeof(($0$)[0]))",
|
|
};
|
|
|
|
void
|
|
CppEvalExpression::PreprocFunction(TypedData* Result)
|
|
{
|
|
PCSTR Args[MAX_CPP_ARGS];
|
|
ULONG ArgsLen[MAX_CPP_ARGS];
|
|
ULONG i;
|
|
CPP_REPLACEMENT* Repl;
|
|
PCSTR Scan;
|
|
|
|
Repl = g_CppPreProcFn;
|
|
for (i = 0; i < DIMA(g_CppPreProcFn); i++)
|
|
{
|
|
// Skip '#' when comparing names.
|
|
if (!strcmp(m_LexemeStart + 1, Repl->Name))
|
|
{
|
|
break;
|
|
}
|
|
|
|
Repl++;
|
|
}
|
|
|
|
if (i == DIMA(g_CppPreProcFn))
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
|
|
DBG_ASSERT(Repl->NumArgs <= MAX_CPP_ARGS);
|
|
|
|
// Accept the name token and verify that the next
|
|
// token is an open paren. Don't accept that token
|
|
// as we're going to switch to grabbing raw characters.
|
|
Accept();
|
|
if (m_Token != CppTokenOpenParen)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
|
|
i = 0;
|
|
for (;;)
|
|
{
|
|
ULONG Nest;
|
|
|
|
// Check for too many arguments.
|
|
if (i >= Repl->NumArgs)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
|
|
//
|
|
// Gather raw text up to the first comma or extra
|
|
// close paren.
|
|
//
|
|
|
|
while (isspace(*m_Lex))
|
|
{
|
|
m_Lex++;
|
|
}
|
|
|
|
Scan = m_Lex;
|
|
Nest = 0;
|
|
for (;;)
|
|
{
|
|
if (!*Scan)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
|
|
if (*Scan == '(')
|
|
{
|
|
Nest++;
|
|
}
|
|
else if ((*Scan == ',' && !Nest) ||
|
|
(*Scan == ')' && Nest-- == 0))
|
|
{
|
|
break;
|
|
}
|
|
|
|
Scan++;
|
|
}
|
|
|
|
Args[i] = m_Lex;
|
|
ArgsLen[i] = (ULONG)(Scan - m_Lex);
|
|
|
|
if (*Scan == ')')
|
|
{
|
|
// Check for too few arguments.
|
|
if (i != Repl->NumArgs - 1)
|
|
{
|
|
EvalError(SYNTAX);
|
|
}
|
|
|
|
m_Lex = Scan;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
m_Lex = Scan + 1;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
// Switch back to token lexing.
|
|
NextToken();
|
|
Match(CppTokenCloseParen);
|
|
|
|
PSTR NewExpr;
|
|
PSTR Dest;
|
|
ULONG ExprLen;
|
|
|
|
//
|
|
// We've accumlated all the arguments, so allocate a destination
|
|
// buffer and do the necessary string replacements.
|
|
// Make the buffer relatively large to allow for complicated
|
|
// replacements.
|
|
//
|
|
|
|
ExprLen = 16384;
|
|
NewExpr = new char[ExprLen];
|
|
if (!NewExpr)
|
|
{
|
|
EvalError(NOMEMORY);
|
|
}
|
|
|
|
Scan = Repl->Repl;
|
|
Dest = NewExpr;
|
|
for (;;)
|
|
{
|
|
if (*Scan == '$')
|
|
{
|
|
//
|
|
// Argument that needs replacement.
|
|
//
|
|
|
|
i = 0;
|
|
Scan++;
|
|
while (isdigit(*Scan))
|
|
{
|
|
i = i * 10 + (ULONG)(*Scan - '0');
|
|
Scan++;
|
|
}
|
|
|
|
if (*Scan != '$' ||
|
|
i >= Repl->NumArgs)
|
|
{
|
|
delete [] NewExpr;
|
|
EvalError(IMPLERR);
|
|
}
|
|
|
|
Scan++;
|
|
|
|
if ((Dest - NewExpr) + ArgsLen[i] >= ExprLen - 1)
|
|
{
|
|
delete [] NewExpr;
|
|
EvalError(OVERFLOW);
|
|
}
|
|
|
|
memcpy(Dest, Args[i], ArgsLen[i]);
|
|
Dest += ArgsLen[i];
|
|
}
|
|
else if (*Scan)
|
|
{
|
|
if ((ULONG)(Dest - NewExpr) >= ExprLen - 1)
|
|
{
|
|
delete [] NewExpr;
|
|
EvalError(OVERFLOW);
|
|
}
|
|
|
|
*Dest++ = *Scan++;
|
|
}
|
|
else
|
|
{
|
|
*Dest = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Evaluate the new expression for the final result.
|
|
//
|
|
|
|
EvalExpression* Eval;
|
|
|
|
Eval = GetEvaluator(DEBUG_EXPR_CPLUSPLUS, TRUE);
|
|
if (!Eval)
|
|
{
|
|
delete [] NewExpr;
|
|
EvalError(NOMEMORY);
|
|
}
|
|
|
|
Eval->InheritStart(this);
|
|
((CppEvalExpression*)Eval)->m_PreprocEval = TRUE;
|
|
|
|
__try
|
|
{
|
|
Eval->Evaluate(NewExpr, NULL, EXPRF_DEFAULT, Result);
|
|
Eval->InheritEnd(this);
|
|
ReleaseEvaluator(Eval);
|
|
}
|
|
__except(CommandExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
delete [] NewExpr;
|
|
ReleaseEvaluators();
|
|
RaiseException(GetExceptionCode(), 0, 0, NULL);
|
|
}
|
|
|
|
delete [] NewExpr;
|
|
}
|