Debugger: Implement member dereferencing in expressions.
CLanguageExpressionEvaluator: - Add tokenizer handling for operators . and ->. - Rework _ParseIdentifier() to work recursively if it sees a deref operator immediately following the current token. This allows one to refer to the value of structure/class members in an expression.
This commit is contained in:
parent
824404e31f
commit
5cd3ae7c0d
@ -58,7 +58,9 @@ enum {
|
|||||||
TOKEN_GT,
|
TOKEN_GT,
|
||||||
TOKEN_GE,
|
TOKEN_GE,
|
||||||
TOKEN_LT,
|
TOKEN_LT,
|
||||||
TOKEN_LE
|
TOKEN_LE,
|
||||||
|
|
||||||
|
TOKEN_MEMBER_PTR
|
||||||
};
|
};
|
||||||
|
|
||||||
static BString TokenTypeToString(int32 type)
|
static BString TokenTypeToString(int32 type)
|
||||||
@ -150,6 +152,10 @@ static BString TokenTypeToString(int32 type)
|
|||||||
token = "<=";
|
token = "<=";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOKEN_MEMBER_PTR:
|
||||||
|
token = "->";
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
token.SetToFormat("Unknown token type %" B_PRId32, type);
|
token.SetToFormat("Unknown token type %" B_PRId32, type);
|
||||||
break;
|
break;
|
||||||
@ -295,6 +301,17 @@ class CLanguageExpressionEvaluator::Tokenizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32 length = fCurrentChar - begin;
|
int32 length = fCurrentChar - begin;
|
||||||
|
if (length == 1 && decimal) {
|
||||||
|
// check for . operator
|
||||||
|
fCurrentChar = begin;
|
||||||
|
if (!_ParseOperator()) {
|
||||||
|
throw ParseException("unexpected character",
|
||||||
|
_CurrentPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
return fCurrentToken;
|
||||||
|
}
|
||||||
|
|
||||||
BString test = temp;
|
BString test = temp;
|
||||||
test << "&_";
|
test << "&_";
|
||||||
double value;
|
double value;
|
||||||
@ -361,16 +378,20 @@ class CLanguageExpressionEvaluator::Tokenizer {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
type = TOKEN_MINUS;
|
if (Peek() == '>') {
|
||||||
length = 1;
|
type = TOKEN_MEMBER_PTR;
|
||||||
|
length = 2;
|
||||||
|
} else {
|
||||||
|
type = TOKEN_MINUS;
|
||||||
|
length = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
if (Peek() == '*') {
|
if (Peek() == '*') {
|
||||||
type = TOKEN_POWER;
|
type = TOKEN_POWER;
|
||||||
length = 2;
|
length = 2;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
type = TOKEN_STAR;
|
type = TOKEN_STAR;
|
||||||
length = 1;
|
length = 1;
|
||||||
}
|
}
|
||||||
@ -453,6 +474,11 @@ class CLanguageExpressionEvaluator::Tokenizer {
|
|||||||
length = 1;
|
length = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
type = TOKEN_MEMBER_PTR;
|
||||||
|
length = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -764,7 +790,7 @@ CLanguageExpressionEvaluator::_ParseUnary()
|
|||||||
|
|
||||||
|
|
||||||
Number
|
Number
|
||||||
CLanguageExpressionEvaluator::_ParseIdentifier()
|
CLanguageExpressionEvaluator::_ParseIdentifier(ValueNode* parentNode)
|
||||||
{
|
{
|
||||||
Token token = fTokenizer->NextToken();
|
Token token = fTokenizer->NextToken();
|
||||||
Number value;
|
Number value;
|
||||||
@ -780,34 +806,41 @@ CLanguageExpressionEvaluator::_ParseIdentifier()
|
|||||||
AutoLocker<ValueNodeContainer> containerLocker(container);
|
AutoLocker<ValueNodeContainer> containerLocker(container);
|
||||||
|
|
||||||
ValueNodeChild* child = NULL;
|
ValueNodeChild* child = NULL;
|
||||||
ValueNodeChild* thisChild = NULL;
|
if (parentNode == NULL) {
|
||||||
for (int32 i = 0; i < container->CountChildren(); i++) {
|
ValueNodeChild* thisChild = NULL;
|
||||||
ValueNodeChild* current = container->ChildAt(i);
|
for (int32 i = 0; i < container->CountChildren(); i++) {
|
||||||
const BString& nodeName = current->Name();
|
ValueNodeChild* current = container->ChildAt(i);
|
||||||
if (nodeName == identifierName) {
|
const BString& nodeName = current->Name();
|
||||||
child = current;
|
if (nodeName == identifierName) {
|
||||||
break;
|
child = current;
|
||||||
} else if (nodeName == "this")
|
break;
|
||||||
thisChild = current;
|
} else if (nodeName == "this")
|
||||||
}
|
thisChild = current;
|
||||||
|
|
||||||
if (child == NULL && thisChild != NULL) {
|
|
||||||
// the name was not found in the variables or parameters,
|
|
||||||
// but we have a class pointer. Try to find the name in the
|
|
||||||
// list of members.
|
|
||||||
_RequestValueIfNeeded(token, thisChild);
|
|
||||||
ValueNode* thisNode = thisChild->Node();
|
|
||||||
// skip the intermediate pointer
|
|
||||||
if (thisNode->GetType()->Kind() == TYPE_ADDRESS
|
|
||||||
&& thisNode->CountChildren() == 1) {
|
|
||||||
thisChild = thisNode->ChildAt(0);
|
|
||||||
|
|
||||||
_RequestValueIfNeeded(token, thisChild);
|
|
||||||
thisNode = thisChild->Node();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32 i = 0; i < thisNode->CountChildren(); i++) {
|
if (child == NULL && thisChild != NULL) {
|
||||||
ValueNodeChild* current = thisNode->ChildAt(i);
|
// the name was not found in the variables or parameters,
|
||||||
|
// but we have a class pointer. Try to find the name in the
|
||||||
|
// list of members.
|
||||||
|
_RequestValueIfNeeded(token, thisChild);
|
||||||
|
ValueNode* thisNode = thisChild->Node();
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
return _ParseIdentifier(thisNode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// skip intermediate address nodes
|
||||||
|
if (parentNode->GetType()->Kind() == TYPE_ADDRESS
|
||||||
|
&& parentNode->CountChildren() == 1) {
|
||||||
|
child = parentNode->ChildAt(0);
|
||||||
|
|
||||||
|
_RequestValueIfNeeded(token, child);
|
||||||
|
parentNode = child->Node();
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
return _ParseIdentifier(parentNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 i = 0; i < parentNode->CountChildren(); i++) {
|
||||||
|
ValueNodeChild* current = parentNode->ChildAt(i);
|
||||||
const BString& nodeName = current->Name();
|
const BString& nodeName = current->Name();
|
||||||
if (nodeName == identifierName) {
|
if (nodeName == identifierName) {
|
||||||
child = current;
|
child = current;
|
||||||
@ -824,8 +857,21 @@ CLanguageExpressionEvaluator::_ParseIdentifier()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_RequestValueIfNeeded(token, child);
|
_RequestValueIfNeeded(token, child);
|
||||||
|
|
||||||
ValueNode* node = child->Node();
|
ValueNode* node = child->Node();
|
||||||
|
|
||||||
|
token = fTokenizer->NextToken();
|
||||||
|
if (token.type == TOKEN_MEMBER_PTR) {
|
||||||
|
token = fTokenizer->NextToken();
|
||||||
|
if (token.type == TOKEN_IDENTIFIER) {
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
return _ParseIdentifier(node);
|
||||||
|
} else {
|
||||||
|
throw ParseException("Expected identifier after member "
|
||||||
|
"dereference.", token.position);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
|
||||||
BVariant variant;
|
BVariant variant;
|
||||||
Value* nodeValue = node->GetValue();
|
Value* nodeValue = node->GetValue();
|
||||||
nodeValue->ToVariant(variant);
|
nodeValue->ToVariant(variant);
|
||||||
|
@ -72,7 +72,7 @@ class CLanguageExpressionEvaluator {
|
|||||||
Number _ParseProduct();
|
Number _ParseProduct();
|
||||||
Number _ParsePower();
|
Number _ParsePower();
|
||||||
Number _ParseUnary();
|
Number _ParseUnary();
|
||||||
Number _ParseIdentifier();
|
Number _ParseIdentifier(ValueNode* parentNode = NULL);
|
||||||
Number _ParseAtom();
|
Number _ParseAtom();
|
||||||
|
|
||||||
void _EatToken(int32 type);
|
void _EatToken(int32 type);
|
||||||
|
Loading…
Reference in New Issue
Block a user