comparison debug.c @ 2169:cb9572145f8e

WIP support for expression parsing in debugger
author Michael Pavone <pavone@retrodev.com>
date Sat, 06 Aug 2022 14:14:15 -0700
parents 8554751f17b5
children ada3130b1396
comparison
equal deleted inserted replaced
2167:fe68a9ad509f 2169:cb9572145f8e
62 cur = &((*cur)->next); 62 cur = &((*cur)->next);
63 } 63 }
64 return cur; 64 return cur;
65 } 65 }
66 66
67 typedef enum {
68 TOKEN_NONE,
69 TOKEN_NUM,
70 TOKEN_NAME,
71 TOKEN_OPER,
72 TOKEN_SIZE
73 } token_type;
74
75 static const char *token_type_names[] = {
76 "TOKEN_NONE",
77 "TOKEN_NUM",
78 "TOKEN_NAME",
79 "TOKEN_OPER",
80 "TOKEN_SIZE"
81 };
82
83 typedef struct {
84 token_type type;
85 union {
86 char *str;
87 char op[3];
88 uint32_t num;
89 } v;
90 } token;
91
92 static token parse_token(char *start, char **end)
93 {
94 while(*start && isblank(*start) && *start != '\n')
95 {
96 ++start;
97 }
98 if (!*start || *start == '\n') {
99 return (token){
100 .type = TOKEN_NONE
101 };
102 *end = start;
103 }
104 if (*start == '$' || (*start == '0' && start[1] == 'x')) {
105 return (token) {
106 .type = TOKEN_NUM,
107 .v = {
108 .num = strtol(start + (*start == '$' ? 1 : 2), end, 16)
109 }
110 };
111 }
112 if (isdigit(*start)) {
113 return (token) {
114 .type = TOKEN_NUM,
115 .v = {
116 .num = strtol(start, end, 10)
117 }
118 };
119 }
120 switch (*start)
121 {
122 case '+':
123 case '-':
124 case '*':
125 case '/':
126 case '&':
127 case '|':
128 case '^':
129 case '~':
130 case '=':
131 case '!':
132 if (*start == '!' && start[1] == '=') {
133 *end = start + 2;
134 return (token) {
135 .type = TOKEN_OPER,
136 .v = {
137 .op = {*start, start[1], 0}
138 }
139 };
140 }
141 *end = start + 1;
142 return (token) {
143 .type = TOKEN_OPER,
144 .v = {
145 .op = {*start, 0}
146 }
147 };
148 case '.':
149 *end = start + 2;
150 return (token) {
151 .type = TOKEN_SIZE,
152 .v = {
153 .op = {start[1], 0}
154 }
155 };
156 }
157 *end = start + 1;
158 while (**end && !isblank(**end) && **end != '.')
159 {
160 ++*end;
161 }
162 char *name = malloc(*end - start + 1);
163 memcpy(name, start, *end - start);
164 name[*end-start] = 0;
165 return (token) {
166 .type = TOKEN_NAME,
167 .v = {
168 .str = name
169 }
170 };
171 }
172
173 typedef enum {
174 EXPR_NONE,
175 EXPR_SCALAR,
176 EXPR_UNARY,
177 EXPR_BINARY,
178 EXPR_SIZE
179 } expr_type;
180
181 typedef struct expr expr;
182
183 struct expr {
184 expr_type type;
185 expr *left;
186 expr *right;
187 token op;
188 };
189
190 static void free_expr(expr *e)
191 {
192 if (!e) {
193 return;
194 }
195 free_expr(e->left);
196 free_expr(e->right);
197 if (e->op.type == TOKEN_NAME) {
198 free(e->op.v.str);
199 }
200 free(e);
201 }
202
203 static expr *parse_scalar(char *start, char **end)
204 {
205 char *after_first;
206 token first = parse_token(start, &after_first);
207 if (!first.type) {
208 return NULL;
209 }
210 if (first.type == TOKEN_SIZE) {
211 fprintf(stderr, "Unexpected TOKEN_SIZE '.%s'\n", first.v.op);
212 return NULL;
213 }
214 if (first.type == TOKEN_OPER) {
215 expr *target = parse_scalar(after_first, end);
216 if (!target) {
217 fprintf(stderr, "Unary expression %s needs value\n", first.v.op);
218 return NULL;
219 }
220 expr *ret = calloc(1, sizeof(expr));
221 ret->type = EXPR_UNARY;
222 ret->op = first;
223 ret->left = target;
224 *end = after_first;
225 return ret;
226 }
227 token second = parse_token(after_first, end);
228 if (second.type != TOKEN_SIZE) {
229 expr *ret = calloc(1, sizeof(expr));
230 ret->type = EXPR_SCALAR;
231 ret->op = first;
232 *end = after_first;
233 return ret;
234 }
235 expr *ret = calloc(1, sizeof(expr));
236 ret->type = EXPR_SIZE;
237 ret->left = calloc(1, sizeof(expr));
238 ret->left->type = EXPR_SCALAR;
239 ret->left->op = second;
240 ret->op = first;
241 return ret;
242 }
243
244 static expr *parse_scalar_or_muldiv(char *start, char **end);
245 static expr *parse_expression(char *start, char **end);
246
247 static expr *maybe_binary(expr *left, char *start, char **end)
248 {
249 char *after_first;
250 token first = parse_token(start, &after_first);
251 if (first.type != TOKEN_OPER) {
252 *end = start;
253 return left;
254 }
255 expr *bin = calloc(1, sizeof(expr));
256 bin->left = left;
257 bin->op = first;
258 bin->type = EXPR_BINARY;
259 switch (first.v.op[0])
260 {
261 case '*':
262 case '/':
263 case '&':
264 case '|':
265 case '^':
266 bin->right = parse_scalar(after_first, end);
267 return maybe_binary(bin, *end, end);
268 case '+':
269 case '-':
270 bin->right = parse_scalar_or_muldiv(after_first, end);
271 return maybe_binary(bin, *end, end);
272 case '=':
273 case '!':
274 bin->right = parse_expression(after_first, end);
275 return bin;
276 default:
277 bin->left = NULL;
278 free(bin);
279 return left;
280 }
281 }
282
283 static expr *maybe_muldiv(expr *left, char *start, char **end)
284 {
285 char *after_first;
286 token first = parse_token(start, &after_first);
287 if (first.type != TOKEN_OPER) {
288 *end = start;
289 return left;
290 }
291 expr *bin = calloc(1, sizeof(expr));
292 bin->left = left;
293 bin->op = first;
294 bin->type = EXPR_BINARY;
295 switch (first.v.op[0])
296 {
297 case '*':
298 case '/':
299 case '&':
300 case '|':
301 case '^':
302 bin->right = parse_scalar(after_first, end);
303 return maybe_binary(bin, *end, end);
304 default:
305 bin->left = NULL;
306 free(bin);
307 return left;
308 }
309 }
310
311 static expr *parse_scalar_or_muldiv(char *start, char **end)
312 {
313 char *after_first;
314 token first = parse_token(start, &after_first);
315 if (!first.type) {
316 return NULL;
317 }
318 if (first.type == TOKEN_SIZE) {
319 fprintf(stderr, "Unexpected TOKEN_SIZE '.%s'\n", first.v.op);
320 return NULL;
321 }
322 if (first.type == TOKEN_OPER) {
323 expr *target = parse_scalar(after_first, end);
324 if (!target) {
325 fprintf(stderr, "Unary expression %s needs value\n", first.v.op);
326 return NULL;
327 }
328 expr *ret = calloc(1, sizeof(expr));
329 ret->type = EXPR_UNARY;
330 ret->op = first;
331 ret->left = target;
332 return ret;
333 }
334 char *after_second;
335 token second = parse_token(after_first, &after_second);
336 if (!second.type) {
337 expr *ret = calloc(1, sizeof(expr));
338 ret->type = EXPR_SCALAR;
339 ret->op = first;
340 *end = after_first;
341 return ret;
342 }
343 if (second.type == TOKEN_OPER) {
344 expr *ret;
345 expr *bin = calloc(1, sizeof(expr));
346 bin->type = EXPR_BINARY;
347 bin->left = calloc(1, sizeof(expr));
348 bin->left->type = EXPR_SCALAR;
349 bin->left->op = first;
350 bin->op = second;
351 switch (second.v.op[0])
352 {
353 case '*':
354 case '/':
355 case '&':
356 case '|':
357 case '^':
358 bin->right = parse_scalar(after_second, end);
359 return maybe_muldiv(bin, *end, end);
360 case '+':
361 case '-':
362 case '=':
363 case '!':
364 ret = bin->left;
365 bin->left = NULL;
366 free_expr(bin);
367 return ret;
368 default:
369 fprintf(stderr, "%s is not a valid binary operator\n", second.v.op);
370 free(bin->left);
371 free(bin);
372 return NULL;
373 }
374 } else if (second.type == TOKEN_SIZE) {
375 expr *value = calloc(1, sizeof(expr));
376 value->type = EXPR_SIZE;
377 value->op = second;
378 value->left = calloc(1, sizeof(expr));
379 value->left->type = EXPR_SCALAR;
380 value->left->op = first;
381 return maybe_muldiv(value, after_second, end);
382 } else {
383 fprintf(stderr, "Unexpected %s after scalar\n", token_type_names[second.type]);
384 return NULL;
385 }
386 }
387
388 static expr *parse_expression(char *start, char **end)
389 {
390 char *after_first;
391 token first = parse_token(start, &after_first);
392 if (!first.type) {
393 return NULL;
394 }
395 if (first.type == TOKEN_SIZE) {
396 fprintf(stderr, "Unexpected TOKEN_SIZE '.%s'\n", first.v.op);
397 return NULL;
398 }
399 if (first.type == TOKEN_OPER) {
400 expr *target = parse_scalar(after_first, end);
401 if (!target) {
402 fprintf(stderr, "Unary expression %s needs value\n", first.v.op);
403 return NULL;
404 }
405 expr *ret = calloc(1, sizeof(expr));
406 ret->type = EXPR_UNARY;
407 ret->op = first;
408 ret->left = target;
409 return ret;
410 }
411 char *after_second;
412 token second = parse_token(after_first, &after_second);
413 if (!second.type) {
414 expr *ret = calloc(1, sizeof(expr));
415 ret->type = EXPR_SCALAR;
416 ret->op = first;
417 *end = after_first;
418 return ret;
419 }
420 if (second.type == TOKEN_OPER) {
421 expr *bin = calloc(1, sizeof(expr));
422 bin->type = EXPR_BINARY;
423 bin->left = calloc(1, sizeof(expr));
424 bin->left->type = EXPR_SCALAR;
425 bin->left->op = first;
426 bin->op = second;
427 switch (second.v.op[0])
428 {
429 case '*':
430 case '/':
431 case '&':
432 case '|':
433 case '^':
434 bin->right = parse_scalar(after_second, end);
435 return maybe_binary(bin, *end, end);
436 case '+':
437 case '-':
438 bin->right = parse_scalar_or_muldiv(after_second, end);
439 return maybe_binary(bin, *end, end);
440 case '=':
441 case '!':
442 bin->right = parse_expression(after_second, end);
443 return bin;
444 default:
445 fprintf(stderr, "%s is not a valid binary operator\n", second.v.op);
446 free(bin->left);
447 free(bin);
448 return NULL;
449 }
450 } else if (second.type == TOKEN_SIZE) {
451 expr *value = calloc(1, sizeof(expr));
452 value->type = EXPR_SIZE;
453 value->op = second;
454 value->left = calloc(1, sizeof(expr));
455 value->left->type = EXPR_SCALAR;
456 value->left->op = first;
457 return maybe_binary(value, after_second, end);
458 } else {
459 fprintf(stderr, "Unexpected %s after scalar\n", token_type_names[second.type]);
460 return NULL;
461 }
462 }
463
464 typedef struct debug_context debug_context;
465 typedef uint8_t (*resolver)(debug_context *context, const char *name, uint32_t *out);
466
467 struct debug_context {
468 resolver resolve;
469 void *system;
470 };
471
472 uint8_t eval_expr(debug_context *context, expr *e, uint32_t *out)
473 {
474 uint32_t right;
475 switch(e->type)
476 {
477 case EXPR_SCALAR:
478 if (e->op.type == TOKEN_NAME) {
479 return context->resolve(context, e->op.v.str, out);
480 } else {
481 *out = e->op.v.num;
482 return 1;
483 }
484 case EXPR_UNARY:
485 if (!eval_expr(context, e->left, out)) {
486 return 0;
487 }
488 switch (e->op.v.op[0])
489 {
490 case '!':
491 *out = !*out;
492 break;
493 case '~':
494 *out = ~*out;
495 break;
496 case '-':
497 *out = -*out;
498 break;
499 default:
500 return 0;
501 }
502 return 1;
503 case EXPR_BINARY:
504 if (!eval_expr(context, e->left, out) || !eval_expr(context, e->right, &right)) {
505 return 0;
506 }
507 switch (e->op.v.op[0])
508 {
509 case '+':
510 *out += right;
511 break;
512 case '-':
513 *out -= right;
514 break;
515 case '*':
516 *out *= right;
517 break;
518 case '/':
519 *out /= right;
520 break;
521 case '&':
522 *out &= right;
523 break;
524 case '|':
525 *out |= right;
526 break;
527 case '^':
528 *out ^= right;
529 break;
530 case '=':
531 *out = *out == right;
532 break;
533 case '!':
534 *out = *out != right;
535 break;
536 default:
537 return 0;
538 }
539 return 1;
540 case EXPR_SIZE:
541 if (!eval_expr(context, e->left, out)) {
542 return 0;
543 }
544 switch (e->op.v.op[0])
545 {
546 case 'b':
547 *out &= 0xFF;
548 break;
549 case 'w':
550 *out &= 0xFFFF;
551 break;
552 }
553 return 1;
554 default:
555 return 0;
556 }
557 }
558
67 void add_display(disp_def ** head, uint32_t *index, char format_char, char * param) 559 void add_display(disp_def ** head, uint32_t *index, char format_char, char * param)
68 { 560 {
69 disp_def * ndisp = malloc(sizeof(*ndisp)); 561 disp_def * ndisp = malloc(sizeof(*ndisp));
70 ndisp->format_char = format_char; 562 ndisp->format_char = format_char;
71 ndisp->param = strdup(param); 563 ndisp->param = strdup(param);
122 } 614 }
123 615
124 uint32_t m68k_read_long(uint32_t address, m68k_context *context) 616 uint32_t m68k_read_long(uint32_t address, m68k_context *context)
125 { 617 {
126 return m68k_read_word(address, context) << 16 | m68k_read_word(address + 2, context); 618 return m68k_read_word(address, context) << 16 | m68k_read_word(address + 2, context);
619 }
620
621 uint8_t resolve_m68k(m68k_context *context, const char *name, uint32_t *out)
622 {
623 if (name[0] == 'd' && name[1] >= '0' && name[1] <= '7') {
624 *out = context->dregs[name[1]-'0'];
625 } else if (name[0] == 'a' && name[1] >= '0' && name[1] <= '7') {
626 *out = context->aregs[name[1]-'0'];
627 } else if (name[0] == 's' && name[1] == 'r') {
628 *out = context->status << 8;
629 for (int flag = 0; flag < 5; flag++) {
630 *out |= context->flags[flag] << (4-flag);
631 }
632 } else if(name[0] == 'c') {
633 *out = context->current_cycle;
634 } else if (name[0] == 'p' && name[1] == 'c') {
635 //FIXME
636 //*out = address;
637 } else {
638 return 0;
639 }
640 return 1;
641 }
642
643 uint8_t resolve_genesis(debug_context *context, const char *name, uint32_t *out)
644 {
645 genesis_context *gen = context->system;
646 if (resolve_m68k(gen->m68k, name, out)) {
647 return 1;
648 }
649 if (!strcmp(name, "f") || !strcmp(name, "frame")) {
650 *out = gen->vdp->frame;
651 return 1;
652 }
653 return 0;
127 } 654 }
128 655
129 void debugger_print(m68k_context *context, char format_char, char *param, uint32_t address) 656 void debugger_print(m68k_context *context, char format_char, char *param, uint32_t address)
130 { 657 {
131 uint32_t value; 658 uint32_t value;
143 case '\0': 670 case '\0':
144 break; 671 break;
145 default: 672 default:
146 fprintf(stderr, "Unrecognized format character: %c\n", format_char); 673 fprintf(stderr, "Unrecognized format character: %c\n", format_char);
147 } 674 }
675 debug_context c = {
676 .resolve = resolve_genesis,
677 .system = context->system
678 };
679 char *after;
680 expr *e = parse_expression(param, &after);
681 if (e) {
682 if (!eval_expr(&c, e, &value)) {
683 fprintf(stderr, "Failed to eval %s\n", param);
684 }
685 free_expr(e);
686 } else {
687 fprintf(stderr, "Failed to parse %s\n", param);
688 }
689 /*
148 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') { 690 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') {
149 value = context->dregs[param[1]-'0']; 691 value = context->dregs[param[1]-'0'];
150 if (param[2] == '.') { 692 if (param[2] == '.') {
151 if (param[3] == 'w') { 693 if (param[3] == 'w') {
152 value &= 0xFFFF; 694 value &= 0xFFFF;
196 value = m68k_read_word(p_addr, context); 738 value = m68k_read_word(p_addr, context);
197 } 739 }
198 } else { 740 } else {
199 fprintf(stderr, "Unrecognized parameter to p: %s\n", param); 741 fprintf(stderr, "Unrecognized parameter to p: %s\n", param);
200 return; 742 return;
201 } 743 }*/
202 if (format_char == 's') { 744 if (format_char == 's') {
203 char tmp[128]; 745 char tmp[128];
204 int i; 746 int i;
205 for (i = 0; i < sizeof(tmp)-1; i++, value++) 747 for (i = 0; i < sizeof(tmp)-1; i++, value++)
206 { 748 {