mirror of https://github.com/mgba-emu/mgba.git
Debugger: Shaving recursive yaks takes a lot of work
This commit is contained in:
parent
1bf1a97023
commit
0979380c74
1
CHANGES
1
CHANGES
|
@ -53,6 +53,7 @@ Other fixes:
|
||||||
- Core: Don't attempt to restore rewind diffs past start of rewind
|
- Core: Don't attempt to restore rewind diffs past start of rewind
|
||||||
- Core: Fix the runloop resuming after a game has crashed (fixes mgba.io/i/2451)
|
- Core: Fix the runloop resuming after a game has crashed (fixes mgba.io/i/2451)
|
||||||
- Core: Fix crash if library can't be opened
|
- Core: Fix crash if library can't be opened
|
||||||
|
- Debugger: Fix crash with extremely long CLI strings
|
||||||
- FFmpeg: Fix crash when encoding audio with some containers
|
- FFmpeg: Fix crash when encoding audio with some containers
|
||||||
- FFmpeg: Fix GIF recording (fixes mgba.io/i/2393)
|
- FFmpeg: Fix GIF recording (fixes mgba.io/i/2393)
|
||||||
- GB: Fix temporary saves
|
- GB: Fix temporary saves
|
||||||
|
|
|
@ -98,6 +98,7 @@ CXX_GUARD_START
|
||||||
} \
|
} \
|
||||||
|
|
||||||
DECLARE_VECTOR(StringList, char*);
|
DECLARE_VECTOR(StringList, char*);
|
||||||
|
DECLARE_VECTOR(IntList, int);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ enum Operation {
|
||||||
|
|
||||||
struct Token {
|
struct Token {
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
TOKEN_ERROR_TYPE,
|
TOKEN_ERROR_TYPE = 0,
|
||||||
TOKEN_UINT_TYPE,
|
TOKEN_UINT_TYPE,
|
||||||
TOKEN_IDENTIFIER_TYPE,
|
TOKEN_IDENTIFIER_TYPE,
|
||||||
TOKEN_OPERATOR_TYPE,
|
TOKEN_OPERATOR_TYPE,
|
||||||
|
@ -60,8 +60,10 @@ struct Token {
|
||||||
|
|
||||||
struct ParseTree {
|
struct ParseTree {
|
||||||
struct Token token;
|
struct Token token;
|
||||||
|
struct ParseTree* p;
|
||||||
struct ParseTree* lhs;
|
struct ParseTree* lhs;
|
||||||
struct ParseTree* rhs;
|
struct ParseTree* rhs;
|
||||||
|
int precedence;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t lexExpression(struct LexVector* lv, const char* string, size_t length, const char* eol);
|
size_t lexExpression(struct LexVector* lv, const char* string, size_t length, const char* eol);
|
||||||
|
|
|
@ -190,14 +190,12 @@ static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointLis
|
||||||
static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) {
|
static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) {
|
||||||
if (breakpoint->d.condition) {
|
if (breakpoint->d.condition) {
|
||||||
parseFree(breakpoint->d.condition);
|
parseFree(breakpoint->d.condition);
|
||||||
free(breakpoint->d.condition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
|
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
|
||||||
if (watchpoint->condition) {
|
if (watchpoint->condition) {
|
||||||
parseFree(watchpoint->condition);
|
parseFree(watchpoint->condition);
|
||||||
free(watchpoint->condition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,11 +226,9 @@ static bool _parseExpression(struct mDebugger* debugger, struct CLIDebugVector*
|
||||||
}
|
}
|
||||||
if (!mDebuggerEvaluateParseTree(debugger, tree, intValue, segmentValue)) {
|
if (!mDebuggerEvaluateParseTree(debugger, tree, intValue, segmentValue)) {
|
||||||
parseFree(tree);
|
parseFree(tree);
|
||||||
free(tree);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
parseFree(tree);
|
parseFree(tree);
|
||||||
free(tree);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,7 +597,6 @@ static struct ParseTree* _parseTree(const char** string) {
|
||||||
if (error) {
|
if (error) {
|
||||||
if (tree) {
|
if (tree) {
|
||||||
parseFree(tree);
|
parseFree(tree);
|
||||||
free(tree);
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
DEFINE_VECTOR(LexVector, struct Token);
|
DEFINE_VECTOR(LexVector, struct Token);
|
||||||
|
|
||||||
|
DEFINE_VECTOR(IntList, int32_t);
|
||||||
|
|
||||||
enum LexState {
|
enum LexState {
|
||||||
LEX_ERROR = -1,
|
LEX_ERROR = -1,
|
||||||
LEX_ROOT = 0,
|
LEX_ROOT = 0,
|
||||||
|
@ -493,16 +495,21 @@ static const int _operatorPrecedence[] = {
|
||||||
[OP_DEREFERENCE] = 2,
|
[OP_DEREFERENCE] = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ParseTree* _parseTreeCreate() {
|
static struct ParseTree* _parseTreeCreate(void) {
|
||||||
struct ParseTree* tree = malloc(sizeof(struct ParseTree));
|
struct ParseTree* tree = malloc(sizeof(struct ParseTree));
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
tree->rhs = 0;
|
tree->p = NULL;
|
||||||
tree->lhs = 0;
|
tree->rhs = NULL;
|
||||||
|
tree->lhs = NULL;
|
||||||
|
tree->precedence = INT_MAX;
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, size_t i, int precedence, int* openParens) {
|
static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, int* openParens) {
|
||||||
struct ParseTree* newTree = 0;
|
struct ParseTree* newTree = NULL;
|
||||||
|
bool pop = false;
|
||||||
|
int precedence = INT_MAX;
|
||||||
|
size_t i = 0;
|
||||||
while (i < LexVectorSize(lv)) {
|
while (i < LexVectorSize(lv)) {
|
||||||
struct Token* token = LexVectorGetPointer(lv, i);
|
struct Token* token = LexVectorGetPointer(lv, i);
|
||||||
int newPrecedence;
|
int newPrecedence;
|
||||||
|
@ -517,27 +524,36 @@ static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, siz
|
||||||
++i;
|
++i;
|
||||||
} else {
|
} else {
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
return i + 1;
|
++i;
|
||||||
|
pop = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TOKEN_SEGMENT_TYPE:
|
case TOKEN_SEGMENT_TYPE:
|
||||||
tree->lhs = _parseTreeCreate();
|
tree->lhs = _parseTreeCreate();
|
||||||
tree->lhs->token.type = TOKEN_UINT_TYPE;
|
tree->lhs->token.type = TOKEN_UINT_TYPE;
|
||||||
tree->lhs->token.uintValue = token->uintValue;
|
tree->lhs->token.uintValue = token->uintValue;
|
||||||
|
tree->lhs->p = tree;
|
||||||
|
tree->lhs->precedence = precedence;
|
||||||
tree->rhs = _parseTreeCreate();
|
tree->rhs = _parseTreeCreate();
|
||||||
|
tree->rhs->p = tree;
|
||||||
|
tree->rhs->precedence = precedence;
|
||||||
tree->token.type = TOKEN_SEGMENT_TYPE;
|
tree->token.type = TOKEN_SEGMENT_TYPE;
|
||||||
i = _parseExpression(tree->rhs, lv, i + 1, precedence, openParens);
|
tree = tree->rhs;
|
||||||
|
++i;
|
||||||
break;
|
break;
|
||||||
case TOKEN_OPEN_PAREN_TYPE:
|
case TOKEN_OPEN_PAREN_TYPE:
|
||||||
++*openParens;
|
++*openParens;
|
||||||
i = _parseExpression(tree, lv, i + 1, INT_MAX, openParens);
|
precedence = INT_MAX;
|
||||||
|
++i;
|
||||||
break;
|
break;
|
||||||
case TOKEN_CLOSE_PAREN_TYPE:
|
case TOKEN_CLOSE_PAREN_TYPE:
|
||||||
if (*openParens <= 0) {
|
if (*openParens <= 0) {
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
}
|
}
|
||||||
--*openParens;
|
--*openParens;
|
||||||
return i + 1;
|
++i;
|
||||||
|
pop = true;
|
||||||
|
break;
|
||||||
case TOKEN_OPERATOR_TYPE:
|
case TOKEN_OPERATOR_TYPE:
|
||||||
if (tree->token.type == TOKEN_ERROR_TYPE) {
|
if (tree->token.type == TOKEN_ERROR_TYPE) {
|
||||||
switch (token->operatorValue) {
|
switch (token->operatorValue) {
|
||||||
|
@ -557,21 +573,44 @@ static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, siz
|
||||||
newPrecedence = _operatorPrecedence[token->operatorValue];
|
newPrecedence = _operatorPrecedence[token->operatorValue];
|
||||||
if (newPrecedence < precedence) {
|
if (newPrecedence < precedence) {
|
||||||
newTree = _parseTreeCreate();
|
newTree = _parseTreeCreate();
|
||||||
*newTree = *tree;
|
memcpy(newTree, tree, sizeof(*tree));
|
||||||
|
if (newTree->lhs) {
|
||||||
|
newTree->lhs->p = newTree;
|
||||||
|
}
|
||||||
|
if (newTree->rhs) {
|
||||||
|
newTree->rhs->p = newTree;
|
||||||
|
}
|
||||||
|
newTree->p = tree;
|
||||||
tree->lhs = newTree;
|
tree->lhs = newTree;
|
||||||
tree->rhs = _parseTreeCreate();
|
tree->rhs = _parseTreeCreate();
|
||||||
|
tree->rhs->p = tree;
|
||||||
|
tree->rhs->precedence = newPrecedence;
|
||||||
|
precedence = newPrecedence;
|
||||||
tree->token = *token;
|
tree->token = *token;
|
||||||
i = _parseExpression(tree->rhs, lv, i + 1, newPrecedence, openParens);
|
tree = tree->rhs;
|
||||||
if (tree->token.type == TOKEN_ERROR_TYPE) {
|
++i;
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return i;
|
pop = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TOKEN_ERROR_TYPE:
|
case TOKEN_ERROR_TYPE:
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
return i + 1;
|
++i;
|
||||||
|
pop = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pop) {
|
||||||
|
if (tree->token.type == TOKEN_ERROR_TYPE && tree->p) {
|
||||||
|
tree->p->token.type = TOKEN_ERROR_TYPE;
|
||||||
|
}
|
||||||
|
tree = tree->p;
|
||||||
|
pop = false;
|
||||||
|
if (!tree) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
precedence = tree->precedence;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,11 +623,13 @@ void parseLexedExpression(struct ParseTree* tree, struct LexVector* lv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tree->token.type = TOKEN_ERROR_TYPE;
|
tree->token.type = TOKEN_ERROR_TYPE;
|
||||||
tree->lhs = 0;
|
tree->lhs = NULL;
|
||||||
tree->rhs = 0;
|
tree->rhs = NULL;
|
||||||
|
tree->p = NULL;
|
||||||
|
tree->precedence = INT_MAX;
|
||||||
|
|
||||||
int openParens = 0;
|
int openParens = 0;
|
||||||
_parseExpression(tree, lv, 0, INT_MAX, &openParens);
|
_parseExpression(tree, lv, &openParens);
|
||||||
if (openParens) {
|
if (openParens) {
|
||||||
if (tree->token.type == TOKEN_IDENTIFIER_TYPE) {
|
if (tree->token.type == TOKEN_IDENTIFIER_TYPE) {
|
||||||
free(tree->token.identifierValue);
|
free(tree->token.identifierValue);
|
||||||
|
@ -607,23 +648,40 @@ void lexFree(struct LexVector* lv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseFree(struct ParseTree* tree) {
|
static void _freeTree(struct ParseTree* tree) {
|
||||||
if (!tree) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tree->lhs) {
|
|
||||||
parseFree(tree->lhs);
|
|
||||||
free(tree->lhs);
|
|
||||||
}
|
|
||||||
if (tree->rhs) {
|
|
||||||
parseFree(tree->rhs);
|
|
||||||
free(tree->rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tree->token.type == TOKEN_IDENTIFIER_TYPE) {
|
if (tree->token.type == TOKEN_IDENTIFIER_TYPE) {
|
||||||
free(tree->token.identifierValue);
|
free(tree->token.identifierValue);
|
||||||
}
|
}
|
||||||
|
free(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseFree(struct ParseTree* tree) {
|
||||||
|
while (tree) {
|
||||||
|
if (tree->lhs) {
|
||||||
|
tree = tree->lhs;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tree->rhs) {
|
||||||
|
tree = tree->rhs;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tree->p) {
|
||||||
|
if (tree->p->lhs == tree) {
|
||||||
|
tree = tree->p;
|
||||||
|
_freeTree(tree->lhs);
|
||||||
|
tree->lhs = NULL;
|
||||||
|
} else if (tree->p->rhs == tree) {
|
||||||
|
tree = tree->p;
|
||||||
|
_freeTree(tree->rhs);
|
||||||
|
tree->rhs = NULL;
|
||||||
|
} else {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_freeTree(tree);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _performOperation(struct mDebugger* debugger, enum Operation operation, int32_t current, int32_t next, int32_t* value, int* segment) {
|
static bool _performOperation(struct mDebugger* debugger, enum Operation operation, int32_t current, int32_t next, int32_t* value, int* segment) {
|
||||||
|
@ -721,56 +779,124 @@ bool mDebuggerEvaluateParseTree(struct mDebugger* debugger, struct ParseTree* tr
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int32_t lhs, rhs;
|
struct IntList stack;
|
||||||
switch (tree->token.type) {
|
int nextBranch;
|
||||||
case TOKEN_UINT_TYPE:
|
bool ok = true;
|
||||||
if (segment) {
|
int32_t tmpVal, tmpSegment;
|
||||||
*segment = -1;
|
|
||||||
}
|
IntListInit(&stack, 0);
|
||||||
*value = tree->token.uintValue;
|
while (ok) {
|
||||||
return true;
|
switch (tree->token.type) {
|
||||||
case TOKEN_SEGMENT_TYPE:
|
case TOKEN_UINT_TYPE:
|
||||||
if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, value, segment)) {
|
nextBranch = 2;
|
||||||
return false;
|
tmpSegment = -1;
|
||||||
}
|
tmpVal = tree->token.uintValue;
|
||||||
return mDebuggerEvaluateParseTree(debugger, tree->lhs, segment, NULL);
|
break;
|
||||||
case TOKEN_OPERATOR_TYPE:
|
case TOKEN_SEGMENT_TYPE:
|
||||||
switch (tree->token.operatorValue) {
|
nextBranch = 0;
|
||||||
case OP_ASSIGN:
|
break;
|
||||||
case OP_ADD:
|
case TOKEN_OPERATOR_TYPE:
|
||||||
case OP_SUBTRACT:
|
switch (tree->token.operatorValue) {
|
||||||
case OP_MULTIPLY:
|
case OP_ASSIGN:
|
||||||
case OP_DIVIDE:
|
case OP_ADD:
|
||||||
case OP_MODULO:
|
case OP_SUBTRACT:
|
||||||
case OP_AND:
|
case OP_MULTIPLY:
|
||||||
case OP_OR:
|
case OP_DIVIDE:
|
||||||
case OP_XOR:
|
case OP_MODULO:
|
||||||
case OP_LESS:
|
case OP_AND:
|
||||||
case OP_GREATER:
|
case OP_OR:
|
||||||
case OP_EQUAL:
|
case OP_XOR:
|
||||||
case OP_NOT_EQUAL:
|
case OP_LESS:
|
||||||
case OP_LOGICAL_AND:
|
case OP_GREATER:
|
||||||
case OP_LOGICAL_OR:
|
case OP_EQUAL:
|
||||||
case OP_LE:
|
case OP_NOT_EQUAL:
|
||||||
case OP_GE:
|
case OP_LOGICAL_AND:
|
||||||
case OP_SHIFT_L:
|
case OP_LOGICAL_OR:
|
||||||
case OP_SHIFT_R:
|
case OP_LE:
|
||||||
if (!mDebuggerEvaluateParseTree(debugger, tree->lhs, &lhs, segment)) {
|
case OP_GE:
|
||||||
return false;
|
case OP_SHIFT_L:
|
||||||
}
|
case OP_SHIFT_R:
|
||||||
// Fall through
|
nextBranch = 0;
|
||||||
default:
|
break;
|
||||||
if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, &rhs, segment)) {
|
default:
|
||||||
return false;
|
nextBranch = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TOKEN_IDENTIFIER_TYPE:
|
||||||
|
if (!mDebuggerLookupIdentifier(debugger, tree->token.identifierValue, &tmpVal, &tmpSegment)) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
nextBranch = 2;
|
||||||
|
break;
|
||||||
|
case TOKEN_ERROR_TYPE:
|
||||||
|
default:
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gotTree = false;
|
||||||
|
while (!gotTree && tree) {
|
||||||
|
int32_t lhs, rhs;
|
||||||
|
|
||||||
|
switch (nextBranch) {
|
||||||
|
case 0:
|
||||||
|
*IntListAppend(&stack) = tmpVal;
|
||||||
|
*IntListAppend(&stack) = tmpSegment;
|
||||||
|
*IntListAppend(&stack) = nextBranch;
|
||||||
|
tree = tree->lhs;
|
||||||
|
gotTree = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
*IntListAppend(&stack) = tmpVal;
|
||||||
|
*IntListAppend(&stack) = tmpSegment;
|
||||||
|
*IntListAppend(&stack) = nextBranch;
|
||||||
|
tree = tree->rhs;
|
||||||
|
gotTree = true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!IntListSize(&stack)) {
|
||||||
|
tree = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nextBranch = *IntListGetPointer(&stack, IntListSize(&stack) - 1);
|
||||||
|
IntListResize(&stack, -1);
|
||||||
|
tree = tree->p;
|
||||||
|
if (nextBranch == 0) {
|
||||||
|
++nextBranch;
|
||||||
|
} else if (tree) {
|
||||||
|
nextBranch = 2;
|
||||||
|
switch (tree->token.type) {
|
||||||
|
case TOKEN_OPERATOR_TYPE:
|
||||||
|
rhs = tmpVal;
|
||||||
|
lhs = *IntListGetPointer(&stack, IntListSize(&stack) - 2);
|
||||||
|
tmpSegment = *IntListGetPointer(&stack, IntListSize(&stack) - 1);
|
||||||
|
ok = _performOperation(debugger, tree->token.operatorValue, lhs, rhs, &tmpVal, &tmpSegment);
|
||||||
|
break;
|
||||||
|
case TOKEN_SEGMENT_TYPE:
|
||||||
|
tmpSegment = *IntListGetPointer(&stack, IntListSize(&stack) - 2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntListResize(&stack, -2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!tree) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return _performOperation(debugger, tree->token.operatorValue, lhs, rhs, value, segment);
|
|
||||||
case TOKEN_IDENTIFIER_TYPE:
|
|
||||||
return mDebuggerLookupIdentifier(debugger, tree->token.identifierValue, value, segment);
|
|
||||||
case TOKEN_ERROR_TYPE:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return false;
|
IntListDeinit(&stack);
|
||||||
|
if (ok) {
|
||||||
|
*value = tmpVal;
|
||||||
|
if (segment) {
|
||||||
|
*segment = tmpSegment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
struct LPTest {
|
struct LPTest {
|
||||||
struct LexVector lv;
|
struct LexVector lv;
|
||||||
struct ParseTree tree;
|
struct ParseTree* tree;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PARSE(STR) \
|
#define PARSE(STR) \
|
||||||
|
@ -18,7 +18,8 @@ struct LPTest {
|
||||||
LexVectorClear(&lp->lv); \
|
LexVectorClear(&lp->lv); \
|
||||||
size_t adjusted = lexExpression(&lp->lv, STR, strlen(STR), ""); \
|
size_t adjusted = lexExpression(&lp->lv, STR, strlen(STR), ""); \
|
||||||
assert_false(adjusted > strlen(STR)); \
|
assert_false(adjusted > strlen(STR)); \
|
||||||
struct ParseTree* tree = &lp->tree; \
|
lp->tree = malloc(sizeof(*lp->tree)); \
|
||||||
|
struct ParseTree* tree = lp->tree; \
|
||||||
parseLexedExpression(tree, &lp->lv)
|
parseLexedExpression(tree, &lp->lv)
|
||||||
|
|
||||||
static int parseSetup(void** state) {
|
static int parseSetup(void** state) {
|
||||||
|
@ -30,7 +31,7 @@ static int parseSetup(void** state) {
|
||||||
|
|
||||||
static int parseTeardown(void** state) {
|
static int parseTeardown(void** state) {
|
||||||
struct LPTest* lp = *state;
|
struct LPTest* lp = *state;
|
||||||
parseFree(&lp->tree);
|
parseFree(lp->tree);
|
||||||
lexFree(&lp->lv);
|
lexFree(&lp->lv);
|
||||||
LexVectorDeinit(&lp->lv);
|
LexVectorDeinit(&lp->lv);
|
||||||
free(lp);
|
free(lp);
|
||||||
|
|
|
@ -28,14 +28,12 @@ static struct mBreakpoint* _lookupBreakpoint(struct mBreakpointList* breakpoints
|
||||||
static void _destroyBreakpoint(struct mBreakpoint* breakpoint) {
|
static void _destroyBreakpoint(struct mBreakpoint* breakpoint) {
|
||||||
if (breakpoint->condition) {
|
if (breakpoint->condition) {
|
||||||
parseFree(breakpoint->condition);
|
parseFree(breakpoint->condition);
|
||||||
free(breakpoint->condition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
|
static void _destroyWatchpoint(struct mWatchpoint* watchpoint) {
|
||||||
if (watchpoint->condition) {
|
if (watchpoint->condition) {
|
||||||
parseFree(watchpoint->condition);
|
parseFree(watchpoint->condition);
|
||||||
free(watchpoint->condition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue