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 },