Mercurial > repos > blastem
comparison debug.c @ 2371:1fe5afe263f3
Initial stab at user-defined functions in debugger language
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 09 Nov 2023 23:30:20 -0800 |
parents | 48cc69b4c358 |
children | 1b21290358a8 |
comparison
equal
deleted
inserted
replaced
2367:48cc69b4c358 | 2371:1fe5afe263f3 |
---|---|
42 debug_func *f = alloc_func(); | 42 debug_func *f = alloc_func(); |
43 f->impl.native = impl; | 43 f->impl.native = impl; |
44 f->max_args = max_args; | 44 f->max_args = max_args; |
45 f->min_args = min_args; | 45 f->min_args = min_args; |
46 f->is_native = 1; | 46 f->is_native = 1; |
47 return (debug_val) { | |
48 .v = { | |
49 .u32 = f - funcs | |
50 }, | |
51 .type = DBG_VAL_FUNC | |
52 }; | |
53 } | |
54 | |
55 static debug_val new_user_func(command_block *block, char **args, int num_args) | |
56 { | |
57 debug_func *f = alloc_func(); | |
58 f->impl.block = *block; | |
59 f->arg_names = args; | |
60 f->max_args = f->min_args = num_args; | |
61 f->is_native = 0; | |
47 return (debug_val) { | 62 return (debug_val) { |
48 .v = { | 63 .v = { |
49 .u32 = f - funcs | 64 .u32 = f - funcs |
50 }, | 65 }, |
51 .type = DBG_VAL_FUNC | 66 .type = DBG_VAL_FUNC |
1114 *end = after_first; | 1129 *end = after_first; |
1115 return ret; | 1130 return ret; |
1116 } | 1131 } |
1117 } | 1132 } |
1118 | 1133 |
1134 static uint8_t execute_block(debug_root *root, command_block * block); | |
1119 uint8_t eval_expr(debug_root *root, expr *e, debug_val *out) | 1135 uint8_t eval_expr(debug_root *root, expr *e, debug_val *out) |
1120 { | 1136 { |
1121 debug_val right; | 1137 debug_val right; |
1122 debug_val *args; | 1138 debug_val *args; |
1123 debug_func *func; | 1139 debug_func *func; |
1330 } | 1346 } |
1331 args = calloc(num_args, sizeof(debug_val)); | 1347 args = calloc(num_args, sizeof(debug_val)); |
1332 for (int i = 0; i < num_args; i++) | 1348 for (int i = 0; i < num_args; i++) |
1333 { | 1349 { |
1334 if (!eval_expr(root, e->right + i, args + i)) { | 1350 if (!eval_expr(root, e->right + i, args + i)) { |
1351 free(args); | |
1335 return 0; | 1352 return 0; |
1336 } | 1353 } |
1337 } | 1354 } |
1338 if (func->is_native) { | 1355 if (func->is_native) { |
1339 *out = func->impl.native(args, num_args); | 1356 *out = func->impl.native(args, num_args); |
1357 free(args); | |
1358 return 1; | |
1340 } else { | 1359 } else { |
1341 //TODO: Implement me | 1360 //TODO: Implement me |
1342 } | 1361 debug_root *func_root = calloc(1, sizeof(debug_root)); |
1343 return 1; | 1362 for (int i = 0; i < num_args; i++) |
1363 { | |
1364 new_user_variable(func_root, func->arg_names[i], args[i]); | |
1365 } | |
1366 free(args); | |
1367 func_root->other_roots = tern_insert_ptr(func_root->other_roots, "parent", root); | |
1368 execute_block(func_root, &func->impl.block); | |
1369 *out = func_root->retval; | |
1370 //FIXME: properly free root | |
1371 tern_free(func_root->variables); | |
1372 tern_free(func_root->other_roots); | |
1373 free(func_root); | |
1374 return 1; | |
1375 } | |
1344 default: | 1376 default: |
1345 return 0; | 1377 return 0; |
1346 } | 1378 } |
1347 } | 1379 } |
1348 | 1380 |
2566 } | 2598 } |
2567 | 2599 |
2568 static uint8_t execute_block(debug_root *root, command_block * block) | 2600 static uint8_t execute_block(debug_root *root, command_block * block) |
2569 { | 2601 { |
2570 uint8_t debugging = 1; | 2602 uint8_t debugging = 1; |
2571 for (int i = 0; i < block->num_commands; i++) | 2603 for (int i = 0; i < block->num_commands && debugging; i++) |
2572 { | 2604 { |
2573 debugging = run_command(root, block->commands + i) && debugging; | 2605 debugging = run_command(root, block->commands + i); |
2574 } | 2606 } |
2575 return debugging; | 2607 return debugging; |
2576 } | 2608 } |
2577 | 2609 |
2578 static uint8_t cmd_if(debug_root *root, parsed_command *cmd) | 2610 static uint8_t cmd_if(debug_root *root, parsed_command *cmd) |
2602 "EXPR_UNARY", | 2634 "EXPR_UNARY", |
2603 "EXPR_BINARY", | 2635 "EXPR_BINARY", |
2604 "EXPR_SIZE", | 2636 "EXPR_SIZE", |
2605 "EXPR_MEM" | 2637 "EXPR_MEM" |
2606 }; | 2638 }; |
2639 | |
2640 static uint8_t cmd_function(debug_root *root, parsed_command *cmd) | |
2641 { | |
2642 debug_root *set_root = root; | |
2643 expr *set_expr = cmd->args[0].parsed; | |
2644 while (set_expr->type == EXPR_NAMESPACE) | |
2645 { | |
2646 set_root = tern_find_ptr(set_root->other_roots, set_expr->op.v.str); | |
2647 if (!set_root) { | |
2648 fprintf(stderr, "%s is not a valid namespace\n", set_expr->op.v.str); | |
2649 return 1; | |
2650 } | |
2651 set_expr = set_expr->left; | |
2652 } | |
2653 if (set_expr->type != EXPR_SCALAR || set_expr->op.type != TOKEN_NAME) { | |
2654 fprintf(stderr, "Arguments to function must be names, bug argument 0 is %s\n", expr_type_names[set_expr->type]); | |
2655 return 1; | |
2656 } | |
2657 debug_var *var = tern_find_ptr(set_root->variables, set_expr->op.v.str); | |
2658 if (var) { | |
2659 fprintf(stderr, "%s is already defined\n", set_expr->op.v.str); | |
2660 return 1; | |
2661 } | |
2662 for (uint32_t i = 1; i < cmd->num_args; i++) | |
2663 { | |
2664 if (cmd->args[i].parsed->type != EXPR_SCALAR || cmd->args[i].parsed->op.type != TOKEN_NAME) { | |
2665 fprintf(stderr, "Arguments to function must be names, bug argument %d is %s\n", i, expr_type_names[cmd->args[i].parsed->type]); | |
2666 return 1; | |
2667 } | |
2668 } | |
2669 char **args = calloc(cmd->num_args - 1, sizeof(char *)); | |
2670 for (uint32_t i = 1; i < cmd->num_args; i++) | |
2671 { | |
2672 args[i - 1] = cmd->args[i].parsed->op.v.str; | |
2673 cmd->args[i].parsed->op.v.str = NULL; | |
2674 } | |
2675 new_readonly_variable(set_root, set_expr->op.v.str, new_user_func(&cmd->block, args, cmd->num_args - 1)); | |
2676 cmd->block.commands = NULL; | |
2677 cmd->block.num_commands = 0; | |
2678 return 1; | |
2679 } | |
2680 | |
2681 static uint8_t cmd_return(debug_root *root, parsed_command *cmd) | |
2682 { | |
2683 root->retval = cmd->args[0].value; | |
2684 return 0; | |
2685 } | |
2607 | 2686 |
2608 static uint8_t cmd_set(debug_root *root, parsed_command *cmd) | 2687 static uint8_t cmd_set(debug_root *root, parsed_command *cmd) |
2609 { | 2688 { |
2610 char *name = NULL; | 2689 char *name = NULL; |
2611 char size = 0; | 2690 char size = 0; |
3420 .desc = "Set a list of debugger commands to be executed when the given breakpoint is hit", | 3499 .desc = "Set a list of debugger commands to be executed when the given breakpoint is hit", |
3421 .impl = cmd_command, | 3500 .impl = cmd_command, |
3422 .min_args = 1, | 3501 .min_args = 1, |
3423 .max_args = 1, | 3502 .max_args = 1, |
3424 .has_block = 1 | 3503 .has_block = 1 |
3504 }, | |
3505 { | |
3506 .names = (const char *[]){ | |
3507 "function", NULL | |
3508 }, | |
3509 .usage = "function NAME [ARGS...]", | |
3510 .desc = "Creates a user-defined function named NAME with arguments ARGS", | |
3511 .impl = cmd_function, | |
3512 .min_args = 1, | |
3513 .max_args = -1, | |
3514 .has_block = 1, | |
3515 .skip_eval = 1 | |
3516 }, | |
3517 { | |
3518 .names = (const char *[]){ | |
3519 "return", NULL | |
3520 }, | |
3521 .usage = "return VALUE", | |
3522 .desc = "Return from a user defined function with the result VALUE", | |
3523 .impl = cmd_return, | |
3524 .min_args = 1, | |
3525 .max_args = 1 | |
3425 }, | 3526 }, |
3426 { | 3527 { |
3427 .names = (const char *[]){ | 3528 .names = (const char *[]){ |
3428 "set", NULL | 3529 "set", NULL |
3429 }, | 3530 }, |