From fc8713b02e4382a0c66f0a063c73a0cc082c5133 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Mon, 27 Oct 2014 11:42:58 -0400 Subject: [PATCH] Debugger: Rework expression evaluator. CLanguageExpressionEvaluator: - Revise to make use of Number class rather than MAPM. In the process, implement support for bitwise operators. SourceLanguage/CLanguageFamily/CLanguageExpressionEvaluator: - Adjust interface for expression evaluation to allow specifying the type to evaluate the expression as. Adjust implementing classes accordingly. ExpressionEvaluationWindow: - Adjust to new expression interface. For now defaults to 64-bit integer type, UI for type selection to be added. --- .../source_language/CLanguageFamily.cpp | 34 ++- .../source_language/CLanguageFamily.h | 2 +- .../source_language/SourceLanguage.cpp | 2 +- .../debugger/source_language/SourceLanguage.h | 2 +- .../CLanguageExpressionEvaluator.cpp | 237 +++++++----------- .../CLanguageExpressionEvaluator.h | 26 +- .../ExpressionEvaluationWindow.cpp | 2 +- 7 files changed, 139 insertions(+), 166 deletions(-) diff --git a/src/apps/debugger/source_language/CLanguageFamily.cpp b/src/apps/debugger/source_language/CLanguageFamily.cpp index b56e2bccb6..eb4884cf7a 100644 --- a/src/apps/debugger/source_language/CLanguageFamily.cpp +++ b/src/apps/debugger/source_language/CLanguageFamily.cpp @@ -11,7 +11,9 @@ #include #include "CLanguageExpressionEvaluator.h" +#include "FloatValue.h" #include "IntegerValue.h" +#include "Number.h" #include "StringValue.h" #include "TeamTypeInformation.h" #include "Type.h" @@ -165,16 +167,36 @@ CLanguageFamily::ParseTypeExpression(const BString& expression, status_t -CLanguageFamily::EvaluateExpression(const BString& expression, Value*& _output) +CLanguageFamily::EvaluateExpression(const BString& expression, + type_code type, Value*& _output) { _output = NULL; CLanguageExpressionEvaluator evaluator; - evaluator.SetSupportHexInput(true); - int64 resultValue; + Number result; try { - resultValue = evaluator.EvaluateToInt64(expression); - BVariant variantValue(resultValue); - _output = new(std::nothrow) IntegerValue(variantValue); + result = evaluator.Evaluate(expression, type); + BVariant resultValue = result.GetValue(); + switch (type) { + case B_INT8_TYPE: + case B_UINT8_TYPE: + case B_INT16_TYPE: + case B_UINT16_TYPE: + case B_INT32_TYPE: + case B_UINT32_TYPE: + case B_INT64_TYPE: + case B_UINT64_TYPE: + _output = new(std::nothrow) IntegerValue(resultValue); + break; + + case B_FLOAT_TYPE: + _output = new(std::nothrow) FloatValue(resultValue.ToFloat()); + break; + + case B_DOUBLE_TYPE: + _output = new(std::nothrow) FloatValue(resultValue.ToDouble()); + break; + } + if (_output == NULL) return B_NO_MEMORY; diff --git a/src/apps/debugger/source_language/CLanguageFamily.h b/src/apps/debugger/source_language/CLanguageFamily.h index e7e9f28d6e..a5e74306ac 100644 --- a/src/apps/debugger/source_language/CLanguageFamily.h +++ b/src/apps/debugger/source_language/CLanguageFamily.h @@ -22,7 +22,7 @@ public: Type*& _resultType) const; virtual status_t EvaluateExpression(const BString& expression, - Value*& _output); + type_code type, Value*& _output); protected: virtual bool IsModifierValid(char modifier) const = 0; diff --git a/src/apps/debugger/source_language/SourceLanguage.cpp b/src/apps/debugger/source_language/SourceLanguage.cpp index 8b11049f94..da77ea7136 100644 --- a/src/apps/debugger/source_language/SourceLanguage.cpp +++ b/src/apps/debugger/source_language/SourceLanguage.cpp @@ -30,7 +30,7 @@ SourceLanguage::ParseTypeExpression(const BString& expression, status_t SourceLanguage::EvaluateExpression(const BString& expression, - Value*& _resultValue) + type_code type, Value*& _resultValue) { return B_NOT_SUPPORTED; } diff --git a/src/apps/debugger/source_language/SourceLanguage.h b/src/apps/debugger/source_language/SourceLanguage.h index 2f607addd2..f609f0f512 100644 --- a/src/apps/debugger/source_language/SourceLanguage.h +++ b/src/apps/debugger/source_language/SourceLanguage.h @@ -32,7 +32,7 @@ public: Type*& _resultType) const; virtual status_t EvaluateExpression(const BString& expression, - Value*& _output); + type_code type, Value*& _output); }; diff --git a/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.cpp b/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.cpp index 4eacb5ec08..27a8a9302b 100644 --- a/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.cpp +++ b/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.cpp @@ -11,17 +11,13 @@ #include "CLanguageExpressionEvaluator.h" +#include "Number.h" + #include -#include #include #include #include -#include - - -static const int32 kMaxDecimalPlaces = 32; - enum { TOKEN_NONE = 0, @@ -47,6 +43,7 @@ enum { TOKEN_BITWISE_AND, TOKEN_BITWISE_OR, TOKEN_BITWISE_NOT, + TOKEN_BITWISE_XOR, TOKEN_EQ, TOKEN_NE, TOKEN_GT, @@ -81,7 +78,7 @@ static BString TokenTypeToString(int32 type) break; case TOKEN_POWER: - token = "^"; + token = "**"; break; case TOKEN_OPENING_BRACKET: @@ -116,6 +113,10 @@ static BString TokenTypeToString(int32 type) token = "~"; break; + case TOKEN_BITWISE_XOR: + token = "^"; + break; + case TOKEN_EQ: token = "=="; break; @@ -153,7 +154,7 @@ struct CLanguageExpressionEvaluator::Token { Token() : string(""), type(TOKEN_NONE), - value(0), + value(0L), position(0) { } @@ -169,7 +170,7 @@ struct CLanguageExpressionEvaluator::Token { Token(const char* string, int32 length, int32 position, int32 type) : string(string, length), type(type), - value(0), + value(), position(position) { } @@ -185,7 +186,7 @@ struct CLanguageExpressionEvaluator::Token { BString string; int32 type; - MAPM value; + Number value; int32 position; }; @@ -198,15 +199,10 @@ class CLanguageExpressionEvaluator::Tokenizer { fCurrentChar(NULL), fCurrentToken(), fReuseToken(false), - fHexSupport(false) + fType(B_INT32_TYPE) { } - void SetSupportHexInput(bool enabled) - { - fHexSupport = enabled; - } - void SetTo(const char* string) { fString = string; @@ -215,6 +211,11 @@ class CLanguageExpressionEvaluator::Tokenizer { fReuseToken = false; } + void SetType(type_code type) + { + fType = type; + } + const Token& NextToken() { if (fCurrentToken.type == TOKEN_END_OF_LINE) @@ -235,7 +236,7 @@ class CLanguageExpressionEvaluator::Tokenizer { bool decimal = *fCurrentChar == '.' || *fCurrentChar == ','; if (decimal || isdigit(*fCurrentChar)) { - if (fHexSupport && *fCurrentChar == '0' && fCurrentChar[1] == 'x') + if (*fCurrentChar == '0' && fCurrentChar[1] == 'x') return _ParseHexNumber(); BString temp; @@ -297,7 +298,7 @@ class CLanguageExpressionEvaluator::Tokenizer { fCurrentToken = Token(begin, length, _CurrentPos() - length, TOKEN_CONSTANT); - fCurrentToken.value = temp.String(); + fCurrentToken.value.SetTo(fType, temp.String()); } else if (isalpha(*fCurrentChar) && *fCurrentChar != 'x') { const char* begin = fCurrentChar; while (*fCurrentChar != 0 && (isalpha(*fCurrentChar) @@ -331,13 +332,6 @@ class CLanguageExpressionEvaluator::Tokenizer { type = TOKEN_SLASH; break; - case 'x': - if (!fHexSupport) { - type = TOKEN_STAR; - break; - } - // fall through - default: throw ParseException("unexpected character", _CurrentPos()); @@ -367,8 +361,14 @@ class CLanguageExpressionEvaluator::Tokenizer { break; case '*': - type = TOKEN_STAR; - length = 1; + if (Peek() == '*') { + type = TOKEN_POWER; + length = 2; + } + else { + type = TOKEN_STAR; + length = 1; + } break; case '/': @@ -382,7 +382,7 @@ class CLanguageExpressionEvaluator::Tokenizer { break; case '^': - type = TOKEN_POWER; + type = TOKEN_BITWISE_XOR; length = 1; break; @@ -497,18 +497,7 @@ class CLanguageExpressionEvaluator::Tokenizer { fCurrentToken = Token(begin, length, _CurrentPos() - length, TOKEN_CONSTANT); - // MAPM has no conversion from long long, so we need to improvise. - uint64 value = strtoll(fCurrentToken.string.String(), NULL, 0); - if (value <= 0x7fffffff) { - fCurrentToken.value = (long)value; - } else { - fCurrentToken.value = (int)(value >> 60); - fCurrentToken.value *= 1 << 30; - fCurrentToken.value += (int)((value >> 30) & 0x3fffffff); - fCurrentToken.value *= 1 << 30; - fCurrentToken.value += (int)(value& 0x3fffffff); - } - + fCurrentToken.value.SetTo(fType, fCurrentToken.string.String(), 16); return fCurrentToken; } @@ -521,7 +510,7 @@ class CLanguageExpressionEvaluator::Tokenizer { const char* fCurrentChar; Token fCurrentToken; bool fReuseToken; - bool fHexSupport; + type_code fType; }; @@ -537,80 +526,22 @@ CLanguageExpressionEvaluator::~CLanguageExpressionEvaluator() } -void -CLanguageExpressionEvaluator::SetSupportHexInput(bool enabled) -{ - fTokenizer->SetSupportHexInput(enabled); -} - - -BString -CLanguageExpressionEvaluator::Evaluate(const char* expressionString) +Number +CLanguageExpressionEvaluator::Evaluate(const char* expressionString, type_code type) { + fTokenizer->SetType(type); fTokenizer->SetTo(expressionString); - MAPM value = _ParseBinary(); + Number value = _ParseBinary(); Token token = fTokenizer->NextToken(); if (token.type != TOKEN_END_OF_LINE) throw ParseException("parse error", token.position); - if (value == 0) - return BString("0"); - - char* buffer = value.toFixPtStringExp(kMaxDecimalPlaces, '.', 0, 0); - if (buffer == NULL) - throw ParseException("out of memory", 0); - - // remove surplus zeros - int32 lastChar = strlen(buffer) - 1; - if (strchr(buffer, '.')) { - while (buffer[lastChar] == '0') - lastChar--; - if (buffer[lastChar] == '.') - lastChar--; - } - - BString result(buffer, lastChar + 1); - free(buffer); - return result; + return value; } -int64 -CLanguageExpressionEvaluator::EvaluateToInt64(const char* expressionString) -{ - fTokenizer->SetTo(expressionString); - - MAPM value = _ParseBinary(); - Token token = fTokenizer->NextToken(); - if (token.type != TOKEN_END_OF_LINE) - throw ParseException("parse error", token.position); - - char buffer[128]; - value.toIntegerString(buffer); - - return strtoll(buffer, NULL, 0); -} - - -double -CLanguageExpressionEvaluator::EvaluateToDouble(const char* expressionString) -{ - fTokenizer->SetTo(expressionString); - - MAPM value = _ParseBinary(); - Token token = fTokenizer->NextToken(); - if (token.type != TOKEN_END_OF_LINE) - throw ParseException("parse error", token.position); - - char buffer[1024]; - value.toString(buffer, sizeof(buffer) - 4); - - return strtod(buffer, NULL); -} - - -MAPM +Number CLanguageExpressionEvaluator::_ParseBinary() { return _ParseSum(); @@ -637,20 +568,20 @@ CLanguageExpressionEvaluator::_ParseBinary() } -MAPM +Number CLanguageExpressionEvaluator::_ParseSum() { // TODO: check isnan()... - MAPM value = _ParseProduct(); + Number value = _ParseProduct(); while (true) { Token token = fTokenizer->NextToken(); switch (token.type) { case TOKEN_PLUS: - value = value + _ParseProduct(); + value += _ParseProduct(); break; case TOKEN_MINUS: - value = value - _ParseProduct(); + value -= _ParseProduct(); break; default: @@ -661,66 +592,86 @@ CLanguageExpressionEvaluator::_ParseSum() } -MAPM +Number CLanguageExpressionEvaluator::_ParseProduct() { - // TODO: check isnan()... - MAPM value = _ParsePower(); + Number value = _ParsePower(); while (true) { Token token = fTokenizer->NextToken(); switch (token.type) { case TOKEN_STAR: - value = value * _ParsePower(); + value *= _ParsePower(); break; case TOKEN_SLASH: { - MAPM rhs = _ParsePower(); - if (rhs == MAPM(0)) + Number rhs = _ParsePower(); + if (rhs == Number(fCurrentType, 0)) throw ParseException("division by zero", token.position); - value = value / rhs; + value /= rhs; break; } case TOKEN_MODULO: { - MAPM rhs = _ParsePower(); - if (rhs == MAPM(0)) + Number rhs = _ParsePower(); + if (rhs == Number()) throw ParseException("modulo by zero", token.position); - value = value % rhs; + value %= rhs; break; } case TOKEN_LOGICAL_AND: - value = (value != MAPM(0) && _ParsePower() != MAPM(0)); + { + Number zero(BVariant(0L)); + value.SetTo(BVariant((int32)((value != zero) + && (_ParsePower() != zero)))); + break; + } case TOKEN_LOGICAL_OR: - value = (value != MAPM(0) || _ParsePower() != MAPM(0)); + { + Number zero(BVariant(0L)); + value.SetTo(BVariant((int32)((value != zero) + || (_ParsePower() != zero)))); + break; + } + + case TOKEN_BITWISE_AND: + value &= _ParsePower(); + break; + + case TOKEN_BITWISE_OR: + value |= _ParsePower(); + break; + + case TOKEN_BITWISE_XOR: + value ^= _ParsePower(); break; case TOKEN_EQ: - value = (value == _ParsePower()); + value.SetTo(BVariant((int32)(value == _ParsePower()))); break; case TOKEN_NE: - value = (value != _ParsePower()); + value.SetTo(BVariant((int32)(value != _ParsePower()))); break; case TOKEN_GT: - value = (value > _ParsePower()); + value.SetTo(BVariant((int32)(value > _ParsePower()))); break; case TOKEN_GE: - value = (value >= _ParsePower()); + value.SetTo(BVariant((int32)(value >= _ParsePower()))); break; case TOKEN_LT: - value = (value < _ParsePower()); + value.SetTo(BVariant((int32)(value < _ParsePower()))); break; case TOKEN_LE: - value = (value <= _ParsePower()); + value.SetTo(BVariant((int32)(value <= _ParsePower()))); break; default: @@ -731,10 +682,10 @@ CLanguageExpressionEvaluator::_ParseProduct() } -MAPM +Number CLanguageExpressionEvaluator::_ParsePower() { - MAPM value = _ParseUnary(); + Number value = _ParseUnary(); while (true) { Token token = fTokenizer->NextToken(); @@ -742,12 +693,16 @@ CLanguageExpressionEvaluator::_ParsePower() fTokenizer->RewindToken(); return value; } - value = value.pow(_ParseUnary()); + + Number power = _ParseUnary(); + Number temp = value; + for (int32 powerValue = power.GetValue().ToInt32(); powerValue > 1; powerValue--) + value *= temp; } } -MAPM +Number CLanguageExpressionEvaluator::_ParseUnary() { Token token = fTokenizer->NextToken(); @@ -761,13 +716,11 @@ CLanguageExpressionEvaluator::_ParseUnary() case TOKEN_MINUS: return -_ParseUnary(); - case TOKEN_BITWISE_AND: - case TOKEN_BITWISE_OR: case TOKEN_BITWISE_NOT: - throw ParseException("Unimplemented bitwise operator", token.position); + return ~_ParseUnary(); case TOKEN_LOGICAL_NOT: - return MAPM(_ParseUnary() == 0); + return Number((int32)(_ParseUnary() == Number(BVariant(0L)))); case TOKEN_IDENTIFIER: return _ParseIdentifier(); @@ -777,7 +730,7 @@ CLanguageExpressionEvaluator::_ParseUnary() return _ParseAtom(); } - return MAPM(0); + return Number(); } @@ -785,21 +738,21 @@ struct Function { const char* name; int argumentCount; void* function; - MAPM value; + Number value; }; -MAPM +Number CLanguageExpressionEvaluator::_ParseIdentifier() { throw ParseException("Identifiers not implemented", 0); - return MAPM(0); + return Number(); } void -CLanguageExpressionEvaluator::_InitArguments(MAPM values[], int32 argumentCount) +CLanguageExpressionEvaluator::_InitArguments(Number values[], int32 argumentCount) { _EatToken(TOKEN_OPENING_BRACKET); @@ -810,7 +763,7 @@ CLanguageExpressionEvaluator::_InitArguments(MAPM values[], int32 argumentCount) } -MAPM +Number CLanguageExpressionEvaluator::_ParseAtom() { Token token = fTokenizer->NextToken(); @@ -824,7 +777,7 @@ CLanguageExpressionEvaluator::_ParseAtom() _EatToken(TOKEN_OPENING_BRACKET); - MAPM value = _ParseBinary(); + Number value = _ParseBinary(); _EatToken(TOKEN_CLOSING_BRACKET); diff --git a/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.h b/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.h index b87a887c4d..d0161788aa 100644 --- a/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.h +++ b/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.h @@ -34,7 +34,7 @@ class ParseException { }; struct Function; -class MAPM; +class Number; class CLanguageExpressionEvaluator { @@ -42,30 +42,28 @@ class CLanguageExpressionEvaluator { CLanguageExpressionEvaluator(); ~CLanguageExpressionEvaluator(); - void SetSupportHexInput(bool enabled); - - BString Evaluate(const char* expressionString); - int64 EvaluateToInt64(const char* expressionString); - double EvaluateToDouble(const char* expressionString); + Number Evaluate(const char* expressionString, + type_code type); private: struct Token; class Tokenizer; private: - MAPM _ParseBinary(); - MAPM _ParseSum(); - MAPM _ParseProduct(); - MAPM _ParsePower(); - MAPM _ParseUnary(); - MAPM _ParseIdentifier(); - void _InitArguments(MAPM values[], + Number _ParseBinary(); + Number _ParseSum(); + Number _ParseProduct(); + Number _ParsePower(); + Number _ParseUnary(); + Number _ParseIdentifier(); + void _InitArguments(Number values[], int32 argumentCount); - MAPM _ParseAtom(); + Number _ParseAtom(); void _EatToken(int32 type); Tokenizer* fTokenizer; + type_code fCurrentType; }; #endif // C_LANGUAGE_EXPRESSION_EVALUATOR_H diff --git a/src/apps/debugger/user_interface/gui/team_window/ExpressionEvaluationWindow.cpp b/src/apps/debugger/user_interface/gui/team_window/ExpressionEvaluationWindow.cpp index 1e2985082a..4042e482dc 100644 --- a/src/apps/debugger/user_interface/gui/team_window/ExpressionEvaluationWindow.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/ExpressionEvaluationWindow.cpp @@ -124,7 +124,7 @@ ExpressionEvaluationWindow::MessageReceived(BMessage* message) Value* value = NULL; BString outputText; status_t error = fLanguage->EvaluateExpression( - fExpressionInput->TextView()->Text(), value); + fExpressionInput->TextView()->Text(), B_INT64_TYPE, value); if (error != B_OK) { if (value != NULL) value->ToString(outputText);