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:
Rene Gollent 2014-10-30 09:51:45 -04:00
parent 824404e31f
commit 5cd3ae7c0d
2 changed files with 80 additions and 34 deletions

View File

@ -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);

View File

@ -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);