uint64 ExpressionParser::_ParseDereference(void** _address, uint32* _size) { int32 starPosition = fTokenizer.CurrentToken().position; // optional "{ ... }" specifying the size to read uint64 size = 4; if (fTokenizer.NextToken().type == TOKEN_OPENING_BRACE) { int32 position = fTokenizer.CurrentToken().position; size = _ParseExpression(); if (size != 1 && size != 2 && size != 4 && size != 8) { snprintf(sTempBuffer, sizeof(sTempBuffer), "invalid size (%" B_PRIu64 ") for unary * operator", size); parse_exception(sTempBuffer, position); } _EatToken(TOKEN_CLOSING_BRACE); } else fTokenizer.RewindToken(); const void* address = (const void*)(addr_t)_ParseUnary(); // read bytes from address into a tempory buffer uint64 buffer; if (debug_memcpy(B_CURRENT_TEAM, &buffer, address, size) != B_OK) { snprintf(sTempBuffer, sizeof(sTempBuffer), "failed to dereference address %p", address); parse_exception(sTempBuffer, starPosition); } // convert the value to uint64 uint64 value = 0; switch (size) { case 1: value = *(uint8*)&buffer; break; case 2: value = *(uint16*)&buffer; break; case 4: value = *(uint32*)&buffer; break; case 8: value = buffer; break; } if (_address != NULL) *_address = (void*)address; if (_size != NULL) *_size = size; return value; }
void ExpressionParser::_GetUnparsedArgument(int& argc, char** argv) { int32 startPosition = fTokenizer.NextToken().position; fTokenizer.RewindToken(); // match parentheses and brackets, but otherwise skip all tokens int32 parentheses = 0; int32 brackets = 0; bool done = false; while (!done) { const Token& token = fTokenizer.NextToken(); switch (token.type) { case TOKEN_OPENING_PARENTHESIS: parentheses++; break; case TOKEN_OPENING_BRACKET: brackets++; break; case TOKEN_CLOSING_PARENTHESIS: if (parentheses > 0) parentheses--; else done = true; break; case TOKEN_CLOSING_BRACKET: if (brackets > 0) brackets--; else done = true; break; case TOKEN_PIPE: case TOKEN_SEMICOLON: if (parentheses == 0 && brackets == 0) done = true; break; case TOKEN_END_OF_LINE: done = true; break; } } int32 endPosition = fTokenizer.CurrentToken().position; fTokenizer.RewindToken(); // add the argument only, if it's not just all spaces const char* arg = fTokenizer.String() + startPosition; int32 argLen = endPosition - startPosition; bool allSpaces = true; for (int32 i = 0; allSpaces && i < argLen; i++) allSpaces = isspace(arg[i]); if (!allSpaces) _AddArgument(argc, argv, arg, argLen); }
uint64 ExpressionParser::_ParseExpression(bool expectAssignment) { const Token& token = fTokenizer.NextToken(); int32 position = token.position; if (token.type == TOKEN_IDENTIFIER) { char variable[MAX_DEBUG_VARIABLE_NAME_LEN]; strlcpy(variable, token.string, sizeof(variable)); int32 assignmentType = fTokenizer.NextToken().type; if (assignmentType & TOKEN_ASSIGN_FLAG) { // an assignment uint64 rhs = _ParseExpression(); // handle the standard assignment separately -- the other kinds // need the variable to be defined if (assignmentType == TOKEN_ASSIGN) { if (!set_debug_variable(variable, rhs)) { snprintf(sTempBuffer, sizeof(sTempBuffer), "failed to set value for variable \"%s\"", variable); parse_exception(sTempBuffer, position); } return rhs; } // variable must be defined if (!is_debug_variable_defined(variable)) { snprintf(sTempBuffer, sizeof(sTempBuffer), "variable \"%s\" not defined in modifying assignment", variable); parse_exception(sTempBuffer, position); } uint64 variableValue = get_debug_variable(variable, 0); // check for division by zero for the respective assignment types if ((assignmentType == TOKEN_SLASH_ASSIGN || assignmentType == TOKEN_MODULO_ASSIGN) && rhs == 0) { parse_exception("division by zero", position); } // compute the new variable value switch (assignmentType) { case TOKEN_PLUS_ASSIGN: variableValue += rhs; break; case TOKEN_MINUS_ASSIGN: variableValue -= rhs; break; case TOKEN_STAR_ASSIGN: variableValue *= rhs; break; case TOKEN_SLASH_ASSIGN: variableValue /= rhs; break; case TOKEN_MODULO_ASSIGN: variableValue %= rhs; break; default: parse_exception("internal error: unknown assignment token", position); break; } set_debug_variable(variable, variableValue); return variableValue; } } else if (token.type == TOKEN_STAR) { void* address; uint32 size; uint64 value = _ParseDereference(&address, &size); int32 assignmentType = fTokenizer.NextToken().type; if (assignmentType & TOKEN_ASSIGN_FLAG) { // an assignment uint64 rhs = _ParseExpression(); // check for division by zero for the respective assignment types if ((assignmentType == TOKEN_SLASH_ASSIGN || assignmentType == TOKEN_MODULO_ASSIGN) && rhs == 0) { parse_exception("division by zero", position); } // compute the new value switch (assignmentType) { case TOKEN_ASSIGN: value = rhs; break; case TOKEN_PLUS_ASSIGN: value += rhs; break; case TOKEN_MINUS_ASSIGN: value -= rhs; break; case TOKEN_STAR_ASSIGN: value *= rhs; break; case TOKEN_SLASH_ASSIGN: value /= rhs; break; case TOKEN_MODULO_ASSIGN: value %= rhs; break; default: parse_exception("internal error: unknown assignment token", position); break; } // convert the value for writing to the address uint64 buffer = 0; switch (size) { case 1: *(uint8*)&buffer = value; break; case 2: *(uint16*)&buffer = value; break; case 4: *(uint32*)&buffer = value; break; case 8: value = buffer; break; } if (debug_memcpy(B_CURRENT_TEAM, address, &buffer, size) != B_OK) { snprintf(sTempBuffer, sizeof(sTempBuffer), "failed to write to address %p", address); parse_exception(sTempBuffer, position); } return value; } } if (expectAssignment) { parse_exception("expected assignment", fTokenizer.CurrentToken().position); } // no assignment -- reset to the identifier position and parse a sum fTokenizer.SetPosition(position); return _ParseSum(false, 0); }