Windows2000/private/windbg64/debugger/ee/deblex.c
2020-09-30 17:12:32 +02:00

1095 lines
27 KiB
C

/*** deblex.c - lexer module for expression evaluator
* Lexer routines for expression evaluator.
*/
#include "debexpr.h"
#include <limits.h>
#include "ldouble.h"
#include "locale.h"
ulong ParseOp (uchar *, token_t *);
ulong CanonOp (uchar *, ptoken_t);
ulong ParseIntConst (uchar *, ptoken_t, uint, UQUAD *);
ulong ParseFloatConst (uchar *, ptoken_t);
ulong ParseIdent (uchar *, ptoken_t, bool_t);
ulong ParseChar (uchar *, ptoken_t);
ulong ParseString (uchar *, ptoken_t);
ulong FakeIdent (uchar *pb, ptoken_t pTok);
bool_t FInRadix (char, uint);
struct Op {
char str[5];
} SEGBASED (_segname("_CODE")) OpStr[] = {
{"\x003""->*"},
{"\x003"">>="},
{"\x003""<<="},
{"\x002""+="},
{"\x002""-="},
{"\x002""*="},
{"\x002""/="},
{"\x002""%="},
{"\x002""^="},
{"\x002""&="},
{"\x002""|="},
{"\x002""<<"},
{"\x002"">>"},
{"\x002""=="},
{"\x002""!="},
{"\x002""<="},
{"\x002"">="},
{"\x002""&&"},
{"\x002""||"},
{"\x002""++"},
{"\x002""--"},
{"\x002""->"},
{"\x001""+"},
{"\x001""-"},
{"\x001""*"},
{"\x001""/"},
{"\x001""%"},
{"\x001""^"},
{"\x001""&"},
{"\x001""|"},
{"\x001""~"},
{"\x001""!"},
{"\x001""="},
{"\x001""<"},
{"\x001"">"},
{"\x001"","},
};
#define OPCNT (sizeof (OpStr)/sizeof (struct Op))
/*** GetDBToken - Fetch next token from expression string
* status = GetDBToken (pbExpr, ptoken, radix, oper)
* Entry pbExpr = far pointer to expression string
* ptoken = pointer to token return location
* radix = default radix for numeric conversion
* oper = previous operator
* Exit *ptoken = token as lexed from input string. If an
* error occurred, the token will be of type OP_badtok.
* If the token is a constant, its value will be determined and
* placed in the token's 'val' field, and its type
* (e.g., T_USHORT) will be placed in the token's 'typ' field.
* If the previous operator is ., ->, ::, then ~ as the next
* character is taken to be part of an identifier
* Returns ERR_NONE if no error
* ERR_... if error encountered in parse
* Calls the appropriate routine to lex the input string. Handles:
* foo Identifiers OP_ident
* +, -, etc. Operators OP_...
* 345 Decimal constants OP_const
* 0123 Octal constants OP_const
* 0xABCD Hexadecimal constants OP_const
* 'a', '\n' Character constants OP_const
* "foo" String constants OP_const
* L"foo" Wide string constants OP_const
* 3.45 Floating point constants OP_const
* HSYM_MARKER handle to symbol follows OP_ident
* The handle to symbol is a hack to make sure that an expression
* can be generated from and locked to the handle to symbol that is
* passed to EEGetTMFromHSYM by the kernel
*/
ulong GetDBToken (uchar *pbExpr, ptoken_t pTok, uint radix, op_t oper)
{
uchar c;
uchar *pbSave = pbExpr;
ulong error;
uint tokLen;
memset (pTok, 0, sizeof (token_t));
pTok->opTok = OP_badtok;
pTok->pbTok = (char *)pbExpr;
c = *pbExpr;
if (c == '~') {
switch (oper) {
case OP_dot:
case OP_pointsto:
case OP_uscope:
case OP_bscope:
case OP_pmember:
case OP_dotmember:
error = ParseIdent (pbExpr, pTok, TRUE);
tokLen = (uint) (pTok->pbEnd - pTok->pbTok);
if ( tokLen > 255 ) //
{
error = ERR_SYNTAX;
}
else
{
pTok->cbTok = (uchar)tokLen;
}
return (error);
}
}
if (_istdigit (c)) {
error = ParseConst (pbExpr, pTok, radix);
}
else if ((c == '\'') || ((c == 'L') && (pbExpr[1] == '\''))) {
error = ParseChar (pbExpr, pTok);
}
else if (((c == 'L') && (pbExpr[1] == '"')) || (c == '"')) {
error = ParseString (pbExpr, pTok);
}
else if ((_istcsymf(c)) || (c == '?') || (c == '$') || (c == '@')) {
error = ParseIdent (pbExpr, pTok, FALSE);
}
else if (c == '.') {
c = *(pbExpr+1);
if ( (c == 0) || (c == '+') || (c=='-') || (c==')')) {
error = ParseIdent (pbExpr, pTok, FALSE);
} else if (_istdigit(c) ) {
error = ParseConst (pbExpr, pTok, radix);
} else {
error = ParseOp (pbExpr, pTok);
}
}
else if (c == HSYM_MARKER) {
error = FakeIdent (pbExpr, pTok);
}
else {
error = ParseOp (pbExpr, pTok);
}
tokLen = (uint) (pTok->pbEnd - pTok->pbTok);
if ( tokLen > 255 ) //
{
error = ERR_SYNTAX;
}
else
{
pTok->cbTok = (uchar)tokLen;
}
// note that caller must compute index of token
return (error);
}
/** ParseConst - Parse an integer or floating point constant string
* error = ParseConst (pb, pTok, radix);
* Entry pb = far pointer to string
* pTok = pointer to return token
* radix = default radix for numeric conversion
* Exit *pTok initialized for constant
* pTok->pbEnd = end of token
* Returns ERR_NONE if no error
* ERR_... if error encountered
*/
ulong ParseConst (uchar *pb, ptoken_t pTok, uint radixin)
{
uint radix = radixin;
bool_t fUSuffix = FALSE;
bool_t fLSuffix = FALSE;
bool_t fFitsInt = FALSE;
bool_t fFitsUint = FALSE;
bool_t fFitsLong = FALSE;
bool_t fFitsULong = FALSE;
bool_t fFitsQuad = FALSE;
UQUAD value;
CV_typ_t typ;
ulong error;
// check beginning of constant for radix specifiers
if ((*pb == '0') && (*(pb + 1) != '.')) {
pb++;
if (_totupper (*pb) == 'X') {
// Hex constant 0x.......
radix = 16;
++pb;
}
else if (_totupper (*pb) == 'N') {
// Decimal constant 0n.......
radix = 10;
++pb;
}
else {
// Octal constant 0........
radix = 8;
--pb;
}
}
// handle 0.xxx first:
if (*pb == '.') {
return (ParseFloatConst (pb, pTok));
// Handle asm constants [0-9]xxxh
} else if (FInRadix(*pb, 10) &&
(error = ParseIntConst (pb, pTok, 16, &value)) == ERR_NONE &&
*pTok->pbEnd == 'h') {
// it worked: keep it and skip over the U and L check.
pb = pTok->pbEnd + 1;
goto SkipUL;
} else if (!FInRadix (*pb, radix)) {
return (ERR_SYNTAX);
} else if ((error = ParseIntConst (pb, pTok, radix, &value)) != ERR_NONE) {
// error parsing as integer constant
return (error);
} else if ((*pTok->pbEnd == '.') || (_totupper (*pTok->pbEnd) == 'E')) {
// Back up and reparse string as floating point
return (ParseFloatConst (pb, pTok));
}
// Check for the 'u' and 'l' modifiers.
pb = (uchar *) pTok->pbEnd;
if (_totupper(*pb) == 'U') {
++pb;
fUSuffix = TRUE;
if (_totupper(*pb) == 'L') {
++pb;
fLSuffix = TRUE;
}
}
else if (_totupper(*pb) == 'L') {
++pb;
fLSuffix = TRUE;
if (_totupper(*pb) == 'U') {
++pb;
fUSuffix = TRUE;
}
}
SkipUL:
// ANSI spec, section 3.1.3.2:
// The type of an integer constant is the first of the corresponding
// list in which its value can be represented. Unsuffixed decimal:
// int, long int, unsigned long int; unsuffixed octal or hexadecimal:
// int, unsigned int, long int, unsigned long int; suffixed by the
// letter u or U: unsigned int, unsigned long int; suffixed by the
// letter l or L: long int, unsigned long int; suffixed by both the
// letters u or U and l or L: unsigned long int.
if (value < 0x8000L) {
fFitsInt = TRUE;
}
if (value < 0x10000L) {
fFitsUint = TRUE;
}
if (value < 0x80000000L) {
fFitsLong = TRUE;
}
if (value < (UQUAD) 0x100000000) {
fFitsULong = TRUE;
}
if (value < (UQUAD) 0x800000000) {
fFitsQuad = TRUE;
}
if (fFitsULong) {
typ = T_ULONG;
if ((fUSuffix) && (fLSuffix)) {
;
}
else if (pExState->state.f32bit) {
if (fUSuffix) {
typ = T_UINT4;
}
else if (fLSuffix) {
if (fFitsLong) {
typ = T_LONG;
}
}
else {
if (fFitsLong) {
typ = T_INT4;
}
else if (radix != 10) {
typ = T_UINT4;
}
}
}
else if (fUSuffix) {
if (fFitsUint) {
typ = T_UINT2;
}
}
else if (fLSuffix) {
if (fFitsLong) {
typ = T_LONG;
}
}
else {
if (fFitsInt) {
typ = T_INT2;
}
else if ((fFitsUint) && (radix != 10)) {
typ = T_UINT2;
}
else if (fFitsLong) {
typ = T_LONG;
}
}
}
else {
// we have a 64 bit integral value. This can only
// be T_QUAD or T_UQUAD, since "really 64bit int types"
// i.e., T_INT8, T_UINT8, etc. are not supported by
// the compiler (ints are 32 bits long in the 32 bit
// world, and 16 bits long in the 16 bit world).
typ = T_UQUAD;
if (fFitsQuad && !fUSuffix) {
typ = T_QUAD;
}
}
pTok->typ = typ;
pTok->opTok = OP_const;
pTok->pbEnd = (char *) pb;
VAL_UQUAD (pTok) = value;
return (ERR_NONE);
}
/*** ParseIntConst - Parse an integer constant
* error = ParseIntConst (pb, pTok, radix, pval)
* Entry pb = pointer to pointer to input string
* pTok = pointer to token return
* radix = radix (8, 10, 16)
* pval = pointer to ulong for value of constant
* Exit pTok updated to reflect token
* Returns ERR_NONE if the input string was successfully parsed as an integer
* constant with the given radix
* ERR_... if error.
*/
ulong
ParseIntConst (
uchar *pb,
ptoken_t pTok,
uint radix,
UQUAD *pval
)
{
uchar c;
uint nextDigit ;
UQUAD maxvalue = _UI64_MAX / radix;
*pval = 0L;
for (;;) {
c = *pb;
if (((radix > 10) && !_istxdigit (c)) ||
((radix <= 10) && !_istdigit (c))) {
// Must have reached the end
break;
}
if (*pval > maxvalue) {
// number will overflow
return (ERR_CONSTANT);
}
if (!FInRadix(c, radix)) {
return (ERR_SYNTAX);
}
*pval *= radix;
if (_istdigit (c = *pb)) {
nextDigit = (c - '0');
}
else {
nextDigit = (_totupper(c) - 'A' + 10);
}
if (( _UI64_MAX - *pval ) < nextDigit ) {
// [cuda:3093 9th Apr 93 sanjays] - additional overflow chk reqd.
// number will overflow.
return (ERR_CONSTANT);
}
else {
*pval += nextDigit ;
}
pb = (uchar *) _tcsinc((_TXCHAR *)pb);
}
pTok->pbEnd = (char *) pb;
return (ERR_NONE);
}
/** ParseFloatConst - Parse a floating-point constant
* fSuccess = ParseFloatConst (pb, pTok);
* Entry pb = pointer to input string
* pTok = pointer to parse token structure
* Exit pTok updated to reflect floating point number if one
* is found.
* Returns ERR_NONE if no error encountered
* ERR_... error
*/
ulong
ParseFloatConst (
uchar *pb,
ptoken_t pTok
)
{
char *pEnd;
char chSave;
CV_typ_t typ;
int cbbuf;
// check for a single '.' - strtold returns 0 in such a case
if (((*pb == '.') && (!_istdigit (*(pb + 1)))) ||
((cbbuf = _tcslen ((TCHAR *)pb)) >= 100)) {
return (ERR_SYNTAX);
}
// Call strtold () to figure out the value. This will also
// return a pointer to the first character which is not
// part of the value -- this allows us to check for an
// 'f' or 'l' suffix character:
// ANSI, Section 3.1.3.1:
// "An unsuffixed floating constant has type double.
// If suffixed by the letter f or F, it has type float.
// If suffixed by the letter l or L, it has type long double."
// always parse numbers in English (especially periods)
setlocale( LC_NUMERIC, "C" );
#if defined(WIN32) && !defined(_MIPS_) && !defined(_ALPHA_) && !defined(_IA64_)
VAL_LDOUBLE(pTok) = LdFromSz (pb, &pEnd);
#else
#if defined(_MIPS_) || defined(_ALPHA_) || defined(_IA64_)
VAL_DOUBLE(pTok) = _tcstod(pb, &pEnd);
#else
VAL_LDOUBLE(pTok) = _strtold (pb, &pEnd);
#endif
#endif
setlocale( LC_NUMERIC, "" ); // revert back to user locale
if (pEnd == pb) {
// Call to strtold () failed
return (ERR_SYNTAX);
}
// Save and check char
pb += pEnd - pb;
chSave = *pb;
if (_totupper (chSave) == 'F') {
pb++;
typ = T_REAL32;
#if defined(_MIPS_) || defined(_ALPHA_)
VAL_FLOAT(pTok) = (float) VAL_DOUBLE(pTok);
#else
VAL_FLOAT(pTok) = FloatFromFloat10 ( VAL_LDOUBLE(pTok) );
#endif
}
else if (_totupper(chSave) == 'L') {
pb++;
#if defined(_MIPS_) || defined(_ALPHA_)
typ = T_REAL64;
#else
typ = T_REAL80;
#endif
}
else {
typ = T_REAL64;
#if !defined(_MIPS_) && !defined(_ALPHA_)
VAL_DOUBLE(pTok) = DoubleFromFloat10 ( VAL_LDOUBLE(pTok) );
#endif
}
pTok->opTok = OP_const;
pTok->typ = typ;
pTok->pbEnd = (char *) pb;
return (ERR_NONE);
}
/*** FakeIdent - Fake an identifier from handle to symbol
* error = FakeIdent (pb, pTok);
* Entry pb = far pointer to string
* pTok = pointer to return token
* Exit *pTok initialized for identifier fro handle to symbol
* pTok->pbEnd = end of token (first non-identifier character)
* Returns ERR_NONE
*/
ulong FakeIdent (uchar *pb, ptoken_t pTok)
{
pTok->opTok = OP_hsym;
pTok->pbEnd = (char *) (pb + sizeof (char) + HSYM_CODE_LEN);
return (ERR_NONE);
}
/*** ParseIdent - Parse an identifier
* error = ParseIdent (pb, pTok, fTilde);
* Entry pb = far pointer to string
* pTok = pointer to return token
* fTilde = TRUE if ~ acceptable as first character
* Exit *pTok initialized for identifier
* pTok->pbEnd = end of token (first non-identifier character)
* Returns ERR_NONE if no error
* ERR_... if error encountered
* Also handles the 'sizeof', 'by', 'wo' and 'dw' operators, since these
* look like identifiers.
*/
ulong ParseIdent (uchar *pb, ptoken_t pTok, bool_t fTilde)
{
int len;
if ( *pb == '.' ) {
++pb;
pTok->opTok = OP_ident;
pTok->pbEnd = (char*)pb;
} else if ((_istcsymf(*pb)) || (*pb == '?') || (*pb == '$') ||
(*pb == '@') || ((*pb == '~') && (fTilde == TRUE))) {
++pb;
while ((_istcsym(*pb)) || (*pb == '?') || (*pb == '$') ||
(*pb == '@')) {
++pb;
}
pTok->opTok = OP_ident;
pTok->pbEnd = (char *) pb;
}
// Check for the 'operator', 'sizeof', 'by', 'wo' and 'dw' operators.
if ((len = (int) (pTok->pbEnd - pTok->pbTok)) == 6) {
if (_tcsncmp (pTok->pbTok, "sizeof", 6) == 0) {
pTok->opTok = OP_sizeof;
}
}
else if (len == 8) {
if (_tcsncmp (pTok->pbTok, "operator", 8) == 0) {
// allow for operator op
return (CanonOp (pb, pTok));
}
}
else if (len == 2) {
// Could be 'by', 'wo' or 'dw'...
if (_tcsnicmp (pTok->pbTok, "BY", 2) == 0) {
pTok->opTok = OP_by;
}
else if (_tcsnicmp (pTok->pbTok, "WO", 2) == 0) {
pTok->opTok = OP_wo;
}
else if (_tcsnicmp (pTok->pbTok, "DW", 2) == 0) {
pTok->opTok = OP_dw;
}
}
// check for special token denoting return value of the
// current function
else if (len == 12) {
if (_tcsnicmp (pTok->pbTok, "$ReturnValue", 12) == 0) {
pTok->opTok = OP_retval;
}
}
return (ERR_NONE);
}
/** CanonOp - canonicalize operator string
* error = CanonOp (pb, pTok)
* Entry pb = pointer to first character after "operator"
* Exit string rewritten to ripple excess white space to the right
* pTok updated to reflect total function name
* pb points to '(' of function call
* Returns ERR_NONE if no error
* ERR_... if error
*/
ulong CanonOp (uchar *pb, ptoken_t pTok)
{
uchar *pOp = pb;
uchar *pTemp;
int i;
while (_istspace (*pb)) {
pb++;
}
if (*pb == 0) {
return (ERR_SYNTAX);
}
if (_istalpha (*pb)) {
// process new, delete
// process
// {[const &| volatile] id [const &| volatile]}
// [{\*[const &| volatile]}*[{\&[const &| volatile]}]]
// Note that the current code only processes a single id
// new (), delete () and type () will pass. All others will
// cause a syntax error later.
pTemp = pb;
while (_istalpha (*pTemp)) {
// skip to end of alpha string
pTemp++;
}
*pOp++ = ' ';
memmove (pOp, pb, (size_t) (pTemp - pb));
pOp += pTemp - pb;
pb = pTemp;
}
else if (*pb == '(') {
// process "( )"
pb++;
while (*pb++ != ')') {
if (!_istspace (*pb)) {
return (ERR_SYNTAX);
}
}
*pOp++ = '(';
*pOp++ = ')';
}
else if (*pb == '[') {
// process "[ ]"
pb++;
while (*pb++ != ']') {
if (!_istspace (*pb)) {
return (ERR_SYNTAX);
}
}
*pOp++ = '[';
*pOp++ = ']';
}
else {
// process operator strings
for ( i = 0; i < OPCNT; i++) {
if (_tcsncmp (OpStr[i].str + 1, (_TXCHAR *) pb, OpStr[i].str[0]) == 0) {
break;
}
}
if (i == OPCNT) {
return (ERR_SYNTAX);
}
memmove (pOp, OpStr[i].str + 1, OpStr[i].str[0]);
pOp += OpStr[i].str[0];
pb += OpStr[i].str[0];
}
// blank out moved characters
pTok->pbEnd = (char *) pOp;
while (pOp < pb) {
*pOp++ = ' ';
}
// skip to the next token and check to make sure it is a (
// the zero check is to allow "bp operator +"
while (_istspace (*pb)) {
pb++;
}
if ((*pb == '(') || (*pb == 0)) {
return (ERR_NONE);
}
else {
return (ERR_SYNTAX);
}
}
/** GetEscapedChar - Parse an escaped character
* error = GetEscapedChar (ppb, pVal);
* Entry ppb = far pointer to far pointer to string. ppb points to
* character after the \
* Exit ppb updated to end of escaped character constant
* *pVal = value of escaped character constant
* Returns ERR_NONE if no error
* ERR_... if error encountered
*/
ulong
GetEscapedChar (
char * *ppb,
ulong *pcbChar,
ushort *pVal
)
{
char c;
uint nval = 0;
char *pbT = *ppb;
c = (char)(**(TCHAR **)ppb);
*ppb = _tcsinc (*ppb);
*pcbChar = (ulong) (*ppb - pbT);
switch (c) {
case 'n':
if (TargetMachine == mptmppc)
*pVal = '\r';
else
*pVal = '\n';
break;
case 't':
*pVal = '\t';
break;
case 'b':
*pVal = '\b';
break;
case 'r':
if (TargetMachine == mptmppc)
*pVal = '\n';
else
*pVal = '\r';
break;
case 'f':
*pVal = '\f';
break;
case 'v':
*pVal = '\v';
break;
case 'a':
*pVal = '\a';
break;
case 'x':
c = (char)(**(TCHAR **)ppb);
if (!FInRadix (c, 16)) {
return (ERR_SYNTAX);
}
for (;;) {
c = (char)(**(TCHAR **)ppb);
if (!FInRadix (c, 16)) {
break;
}
nval *= 16;
if (_istdigit ((_TUCHAR)c)) {
nval += c - '0';
}
else {
nval += _totupper((_TUCHAR)c) - 'A' + 10;
}
if (nval > 255) {
return (ERR_CONSTANT);
}
*ppb = _tcsinc (*ppb);
}
*pVal = (uchar)nval;
break;
default:
if (FInRadix (c, 8)) {
// Octal character constant
nval = (c - '0');
for (;;) {
c = (char)(**(TCHAR **)ppb);
if (!_istdigit ((_TUCHAR)c)) {
break;
}
if (!FInRadix (c, 8)) {
return (ERR_SYNTAX);
}
nval = nval * 8 + (c - '0');
if (nval > 255) {
return (ERR_CONSTANT);
}
*ppb = _tcsinc (*ppb);
}
*pVal = (uchar)nval;
}
else {
*pVal = c;
}
break;
}
return (ERR_NONE);
}
/** ParseChar - Parse an character constant
* error = ParseChar (pb, pTok);
* Entry pb = far pointer to string
* pTok = pointer to return token
* Exit *pTok initialized for character constant
* pTok->pbEnd = end of token
* Returns ERR_NONE if no error
* ERR_... if error encountered
*/
ulong
ParseChar (
uchar *pb,
ptoken_t pTok
)
{
unsigned int value = 0;
ulong cbTotal = 0;
ulong retval;
if (*(TCHAR *)pb == _T('L') ) {
// skip initial L if L'
pb = (uchar *) _tcsinc ((_TXCHAR *) pb);
}
DASSERT( *(TCHAR *)pb == _T('\'') );
pb = (uchar *) _tcsinc ((_TXCHAR *)pb);
if ((*(TCHAR *)pb == _T('\'') ) || (*(TCHAR *)pb == 0)) {
return (ERR_SYNTAX);
}
while ((*(TCHAR *)pb != _T('\'') ) && (*(TCHAR *)pb != 0)) {
uint c = 0;
uchar * pbT;
ulong cbChar;
pbT = pb;
pb = (uchar *) _tcsinc ((_TXCHAR *)pb);
cbChar = (ulong) (pb - pbT);
switch ( cbChar ) {
case 1:
c = *(uchar *)pbT;
break;
case 2:
c = *(ushort *)pbT;
break;
default:
pTok->opTok = OP_badtok;
return ( ERR_CONSTANT );
}
if ( c == _T('\\') ) {
ushort escVal;
// Escaped character constant
if ((retval = GetEscapedChar ((_TXCHAR **)&pb, &cbChar, &escVal)) != ERR_NONE) {
return (retval);
}
c = (TCHAR)escVal;
}
value = (value << (cbChar * 8)) | (ushort)c;
cbTotal += cbChar;
}
if ( *(TCHAR *)pb != _T('\'') ) {
return (ERR_MISSINGSQ);
}
pb = (uchar *) _tcsinc ((_TXCHAR *) pb);
pTok->opTok = OP_const;
switch ( cbTotal ) {
case 1:
VAL_CHAR(pTok) = (char) value;
pTok->typ = T_RCHAR;
break;
case 2:
VAL_SHORT(pTok) = (short)value;
pTok->typ = T_SHORT;
break;
case 3:
case 4:
VAL_LONG(pTok) = (long)value;
pTok->typ = T_LONG;
break;
default:
pTok->opTok = OP_badtok;
return ( ERR_CONSTANT );
}
pTok->pbEnd = (char *) pb;
return (ERR_NONE);
}
/** ParseString - Parse a string constant "..." or L"..."
* error = ParseString (pb, pTok, fWide);
* Entry pb = far pointer to string
* pTok = pointer to return token
* Exit *pTok initialized for string constant
* pTok->pbEnd = end of token
* Returns ERR_NONE if no error
* ERR_... if error encountered
* Note The string pointer will point to the initial " or L"
* and the byte count will include beginning " or L" and the
* ending ". The evaluator will have to adjust for the extra
* characters and store the proper data.
*/
ulong ParseString (uchar *pb, ptoken_t pTok)
{
if (*pb =='L') {
// skip initial L if L"
pb++;
}
// skip initial "
DASSERT (*pb == '"');
pb++;
// search for ending double quote
while ((*pb != 0) && (*pb != '"')) {
if (*pb == '\\' && *(pb + 1) == '"') {
pb++;
}
pb = (uchar *) _tcsinc((_TXCHAR *) pb);
}
if (!*pb) {
// reached end of string
return (ERR_MISSINGDQ);
}
pTok->opTok = OP_const;
if (pExState->state.f32bit) {
pTok->typ = T_32PRCHAR;
}
else {
pTok->typ = T_PRCHAR;
}
pTok->pbEnd = (char *) (pb + 1);
return (ERR_NONE);
}
/*** FInRadix - Is character appropriate for radix?
* fOK = FInRadix (ch, radix)
* Entry ch = character to check
* radix = 8, 10, 16
* Exit none
* Returns TRUE if character is in radix
* FALSE if not.
*/
bool_t FInRadix (char ch, uint radix)
{
switch (radix) {
case 8:
if (ch >= '8' || ch < '0') {
return (FALSE);
}
// Fall through
case 10:
return (_istdigit((_TUCHAR)ch));
case 16:
return (_istxdigit((_TUCHAR)ch));
default:
DASSERT (FALSE);
return (FALSE);
}
}