~ubuntu-branches/debian/squeeze/stella/squeeze

« back to all changes in this revision

Viewing changes to src/debugger/DebuggerParser.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Mario Iseli
  • Date: 2006-04-08 18:38:25 UTC
  • mfrom: (1.1.2 upstream) (2.1.1 etch)
  • Revision ID: james.westby@ubuntu.com-20060408183825-vu1jk57rk929derx
* New Maintainer (Closes: #361345)
* New upstream release (Closes: #349725)
* Build-Depend now on libslang2-dev (Closes: #325577)
* Complete rebuild of debian/, upgraded to policy-standards
  3.6.2 and compat-level 5.
* Removed stellarc since stella only reads ~/.stellarc and even
  works without a first config.
* New debian/watch file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//============================================================================
 
2
//
 
3
//   SSSS    tt          lll  lll       
 
4
//  SS  SS   tt           ll   ll        
 
5
//  SS     tttttt  eeee   ll   ll   aaaa 
 
6
//   SSSS    tt   ee  ee  ll   ll      aa
 
7
//      SS   tt   eeeeee  ll   ll   aaaaa  --  "An Atari 2600 VCS Emulator"
 
8
//  SS  SS   tt   ee      ll   ll  aa  aa
 
9
//   SSSS     ttt  eeeee llll llll  aaaaa
 
10
//
 
11
// Copyright (c) 1995-2005 by Bradford W. Mott and the Stella team
 
12
//
 
13
// See the file "license" for information on usage and redistribution of
 
14
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
15
//
 
16
// $Id: DebuggerParser.cxx,v 1.89 2005/12/19 02:19:48 stephena Exp $
 
17
//============================================================================
 
18
 
 
19
#include "bspf.hxx"
 
20
#include <iostream>
 
21
#include <fstream>
 
22
 
 
23
#include "Dialog.hxx"
 
24
#include "Debugger.hxx"
 
25
#include "CpuDebug.hxx"
 
26
#include "DebuggerParser.hxx"
 
27
#include "YaccParser.hxx"
 
28
#include "M6502.hxx"
 
29
#include "Expression.hxx"
 
30
#include "RomWidget.hxx"
 
31
 
 
32
#ifdef CHEATCODE_SUPPORT
 
33
  #include "CheatManager.hxx"
 
34
#endif
 
35
 
 
36
#include "DebuggerParser.hxx"
 
37
 
 
38
Command DebuggerParser::commands[] = {
 
39
        {
 
40
                "a",
 
41
                "Set Accumulator to value xx",
 
42
                true,
 
43
                true,
 
44
                { kARG_WORD, kARG_END_ARGS },
 
45
                &DebuggerParser::executeA
 
46
        },
 
47
 
 
48
        {
 
49
                "bank",
 
50
                "Show # of banks (with no args), Switch to bank (with 1 arg)",
 
51
                false,
 
52
                true,
 
53
                { kARG_WORD, kARG_END_ARGS },
 
54
                &DebuggerParser::executeBank
 
55
        },
 
56
 
 
57
        {
 
58
                "base",
 
59
                "Set default base (hex, dec, or bin)",
 
60
                true,
 
61
                true,
 
62
                { kARG_BASE_SPCL, kARG_END_ARGS },
 
63
                &DebuggerParser::executeBase
 
64
        },
 
65
 
 
66
        {
 
67
                "break",
 
68
                "Set/clear breakpoint at address (default: current pc)",
 
69
                false,
 
70
                true,
 
71
                { kARG_WORD, kARG_END_ARGS },
 
72
                &DebuggerParser::executeBreak
 
73
        },
 
74
 
 
75
        {
 
76
                "breakif",
 
77
                "Set breakpoint on condition",
 
78
                true,
 
79
                false,
 
80
                { kARG_WORD, kARG_END_ARGS },
 
81
                &DebuggerParser::executeBreakif
 
82
        },
 
83
 
 
84
        {
 
85
                "c",
 
86
                "Carry Flag: set (to 0 or 1), or toggle (no arg)",
 
87
                false,
 
88
                true,
 
89
                { kARG_BOOL, kARG_END_ARGS },
 
90
                &DebuggerParser::executeC
 
91
        },
 
92
 
 
93
#ifdef CHEATCODE_SUPPORT
 
94
        {
 
95
                "cheat",
 
96
                "Use a cheat code (see Stella manual for cheat types)",
 
97
                false,
 
98
                false,
 
99
                { kARG_LABEL, kARG_END_ARGS },
 
100
                &DebuggerParser::executeCheat
 
101
        },
 
102
#endif
 
103
 
 
104
        {
 
105
                "clearbreaks",
 
106
                "Clear all breakpoints",
 
107
                false,
 
108
                true,
 
109
                { kARG_END_ARGS },
 
110
                &DebuggerParser::executeClearbreaks
 
111
        },
 
112
 
 
113
        {
 
114
                "cleartraps",
 
115
                "Clear all traps",
 
116
                false,
 
117
                false,
 
118
                { kARG_END_ARGS },
 
119
                &DebuggerParser::executeCleartraps
 
120
        },
 
121
 
 
122
        {
 
123
                "clearwatches",
 
124
                "Clear all watches",
 
125
                false,
 
126
                false,
 
127
                { kARG_END_ARGS },
 
128
                &DebuggerParser::executeClearwatches
 
129
        },
 
130
 
 
131
        {
 
132
                "colortest",
 
133
                "Color Test",
 
134
                true,
 
135
                false,
 
136
                { kARG_WORD, kARG_END_ARGS },
 
137
                &DebuggerParser::executeColortest
 
138
        },
 
139
 
 
140
        {
 
141
                "d",
 
142
                "Decimal Flag: set (to 0 or 1), or toggle (no arg)",
 
143
                false,
 
144
                true,
 
145
                { kARG_BOOL, kARG_END_ARGS },
 
146
                &DebuggerParser::executeD
 
147
        },
 
148
 
 
149
        {
 
150
                "define",
 
151
                "Define label",
 
152
                true,
 
153
                true,
 
154
                { kARG_LABEL, kARG_WORD, kARG_END_ARGS },
 
155
                &DebuggerParser::executeDefine
 
156
        },
 
157
 
 
158
        {
 
159
                "delbreakif",
 
160
                "Delete conditional break created with breakif",
 
161
                true,
 
162
                false,
 
163
                { kARG_WORD, kARG_END_ARGS },
 
164
                &DebuggerParser::executeDelbreakif
 
165
        },
 
166
 
 
167
        {
 
168
                "delwatch",
 
169
                "Delete watch",
 
170
                true,
 
171
                false,
 
172
                { kARG_WORD, kARG_END_ARGS },
 
173
                &DebuggerParser::executeDelwatch
 
174
        },
 
175
 
 
176
        {
 
177
                "disasm",
 
178
                "Disassemble from address (default=pc)",
 
179
                false,
 
180
                false,
 
181
                { kARG_WORD, kARG_END_ARGS },
 
182
                &DebuggerParser::executeDisasm
 
183
        },
 
184
 
 
185
        {
 
186
                "dump",
 
187
                "Dump 128 bytes of memory at address",
 
188
                true,
 
189
                false,
 
190
                { kARG_WORD, kARG_END_ARGS },
 
191
                &DebuggerParser::executeDump
 
192
        },
 
193
 
 
194
        {
 
195
                "exec",
 
196
                "Execute script file",
 
197
                true,
 
198
                true,
 
199
                { kARG_FILE, kARG_END_ARGS },
 
200
                &DebuggerParser::executeExec
 
201
        },
 
202
 
 
203
        {
 
204
                "frame",
 
205
                "Advance emulation by xx frames (default=1)",
 
206
                false,
 
207
                true,
 
208
                { kARG_WORD, kARG_END_ARGS },
 
209
                &DebuggerParser::executeFrame
 
210
        },
 
211
 
 
212
        {
 
213
                "function",
 
214
                "Define expression as a function for later use",
 
215
                false,
 
216
                false,
 
217
                { kARG_LABEL, kARG_WORD, kARG_END_ARGS },
 
218
                &DebuggerParser::executeFunction
 
219
        },
 
220
 
 
221
        {
 
222
                "height",
 
223
                "Change height of debugger window",
 
224
                true,
 
225
                false,
 
226
                { kARG_WORD, kARG_END_ARGS },
 
227
                &DebuggerParser::executeHeight
 
228
        },
 
229
 
 
230
        {
 
231
                "help",
 
232
                "This cruft",
 
233
                false,
 
234
                false,
 
235
                { kARG_END_ARGS },
 
236
                &DebuggerParser::executeHelp
 
237
        },
 
238
 
 
239
        {
 
240
                "list",
 
241
                "List source (if loaded with loadlst)",
 
242
                false,
 
243
                false,
 
244
                { kARG_WORD, kARG_END_ARGS },
 
245
                &DebuggerParser::executeList
 
246
        },
 
247
 
 
248
        {
 
249
                "listbreaks",
 
250
                "List breakpoints",
 
251
                false,
 
252
                false,
 
253
                { kARG_END_ARGS },
 
254
                &DebuggerParser::executeListbreaks
 
255
        },
 
256
 
 
257
        {
 
258
                "listtraps",
 
259
                "List traps",
 
260
                false,
 
261
                false,
 
262
                { kARG_END_ARGS },
 
263
                &DebuggerParser::executeListtraps
 
264
        },
 
265
 
 
266
        {
 
267
                "listwatches",
 
268
                "List watches",
 
269
                false,
 
270
                false,
 
271
                { kARG_END_ARGS },
 
272
                &DebuggerParser::executeListwatches
 
273
        },
 
274
 
 
275
        {
 
276
                "loadstate",
 
277
                "Load emulator state (0-9)",
 
278
                true,
 
279
                true,
 
280
                { kARG_WORD, kARG_END_ARGS },
 
281
                &DebuggerParser::executeLoadstate
 
282
        },
 
283
 
 
284
        {
 
285
                "loadlist",
 
286
                "Load DASM listing file",
 
287
                true,
 
288
                true,
 
289
                { kARG_FILE, kARG_END_ARGS },
 
290
                &DebuggerParser::executeLoadlist
 
291
        },
 
292
 
 
293
        {
 
294
                "loadsym",
 
295
                "Load symbol file",
 
296
                true,
 
297
                true,
 
298
                { kARG_FILE, kARG_END_ARGS },
 
299
                &DebuggerParser::executeLoadsym
 
300
        },
 
301
 
 
302
        {
 
303
                "n",
 
304
                "Negative Flag: set (to 0 or 1), or toggle (no arg)",
 
305
                false,
 
306
                true,
 
307
                { kARG_BOOL, kARG_END_ARGS },
 
308
                &DebuggerParser::executeN
 
309
        },
 
310
 
 
311
        {
 
312
                "pc",
 
313
                "Set Program Counter to address",
 
314
                true,
 
315
                true,
 
316
                { kARG_WORD, kARG_END_ARGS },
 
317
                &DebuggerParser::executePc
 
318
        },
 
319
 
 
320
        {
 
321
                "poke",
 
322
                "Set address to value. Can give multiple values (for address+1, etc)",
 
323
                true,
 
324
                true,
 
325
                { kARG_WORD, kARG_MULTI_BYTE },
 
326
                &DebuggerParser::executeRam
 
327
        },
 
328
 
 
329
        {
 
330
                "print",
 
331
                "Evaluate and print expression in hex/dec/binary",
 
332
                true,
 
333
                false,
 
334
                { kARG_WORD, kARG_END_ARGS },
 
335
                &DebuggerParser::executePrint
 
336
        },
 
337
 
 
338
        {
 
339
                "ram",
 
340
                "Show RAM contents (no args), or set address xx to value yy",
 
341
                false,
 
342
                true,
 
343
                { kARG_WORD, kARG_MULTI_BYTE },
 
344
                &DebuggerParser::executeRam
 
345
        },
 
346
 
 
347
        {
 
348
                "reload",
 
349
                "Reload ROM and symbol file",
 
350
                false,
 
351
                true,
 
352
                { kARG_END_ARGS },
 
353
                &DebuggerParser::executeReload
 
354
        },
 
355
 
 
356
        {
 
357
                "reset",
 
358
                "Reset 6507 to init vector (does not reset TIA, RIOT)",
 
359
                false,
 
360
                true,
 
361
                { kARG_END_ARGS },
 
362
                &DebuggerParser::executeReset
 
363
        },
 
364
 
 
365
        {
 
366
                "riot",
 
367
                "Show RIOT timer/input status",
 
368
                false,
 
369
                false,
 
370
                { kARG_END_ARGS },
 
371
                &DebuggerParser::executeRiot
 
372
        },
 
373
 
 
374
        {
 
375
                "rom",
 
376
                "Change ROM contents",
 
377
                true,
 
378
                true,
 
379
                { kARG_WORD, kARG_MULTI_BYTE },
 
380
                &DebuggerParser::executeRom
 
381
        },
 
382
 
 
383
        {
 
384
                "run",
 
385
                "Exit debugger, return to emulator",
 
386
                false,
 
387
                false,
 
388
                { kARG_END_ARGS },
 
389
                &DebuggerParser::executeRun
 
390
        },
 
391
 
 
392
        {
 
393
                "runto",
 
394
                "Run until first occurrence of string in disassembly",
 
395
                false,
 
396
                true,
 
397
                { kARG_LABEL, kARG_END_ARGS },
 
398
                &DebuggerParser::executeRunTo
 
399
        },
 
400
 
 
401
        {
 
402
                "s",
 
403
                "Set Stack Pointer to value xx",
 
404
                true,
 
405
                true,
 
406
                { kARG_WORD, kARG_END_ARGS },
 
407
                &DebuggerParser::executeS
 
408
        },
 
409
 
 
410
        {
 
411
                "save",
 
412
                "Save breaks, watches, traps as a .stella script file",
 
413
                true,
 
414
                false,
 
415
                { kARG_FILE, kARG_END_ARGS },
 
416
                &DebuggerParser::executeSave
 
417
        },
 
418
 
 
419
        {
 
420
                "saverom",
 
421
                "Save (possibly patched) ROM to file",
 
422
                true,
 
423
                false,
 
424
                { kARG_FILE, kARG_END_ARGS },
 
425
                &DebuggerParser::executeSaverom
 
426
        },
 
427
 
 
428
        {
 
429
                "saveses",
 
430
                "Save console session to file",
 
431
                true,
 
432
                false,
 
433
                { kARG_FILE, kARG_END_ARGS },
 
434
                &DebuggerParser::executeSaveses
 
435
        },
 
436
 
 
437
        {
 
438
                "savestate",
 
439
                "Save emulator state (valid args 0-9)",
 
440
                true,
 
441
                false,
 
442
                { kARG_WORD, kARG_END_ARGS },
 
443
                &DebuggerParser::executeSavestate
 
444
        },
 
445
 
 
446
        {
 
447
                "savesym",
 
448
                "Save symbols to file",
 
449
                true,
 
450
                false,
 
451
                { kARG_FILE, kARG_END_ARGS },
 
452
                &DebuggerParser::executeSavesym
 
453
        },
 
454
 
 
455
        {
 
456
                "scanline",
 
457
                "Advance emulation by xx scanlines (default=1)",
 
458
                false,
 
459
                true,
 
460
                { kARG_WORD, kARG_END_ARGS },
 
461
                &DebuggerParser::executeScanline
 
462
        },
 
463
 
 
464
        {
 
465
                "step",
 
466
                "Single step CPU (optionally, with count)",
 
467
                false,
 
468
                true,
 
469
                { kARG_WORD, kARG_END_ARGS },
 
470
                &DebuggerParser::executeStep
 
471
        },
 
472
 
 
473
        {
 
474
                "tia",
 
475
                "Show TIA state (NOT FINISHED YET)",
 
476
                false,
 
477
                false,
 
478
                { kARG_END_ARGS },
 
479
                &DebuggerParser::executeTia
 
480
        },
 
481
 
 
482
        {
 
483
                "trace",
 
484
                "Single step CPU (optionally, with count), subroutines count as one instruction",
 
485
                false,
 
486
                true,
 
487
                { kARG_WORD, kARG_END_ARGS },
 
488
                &DebuggerParser::executeTrace
 
489
        },
 
490
 
 
491
        {
 
492
                "trap",
 
493
                "Trap read and write accesses to address",
 
494
                true,
 
495
                false,
 
496
                { kARG_WORD, kARG_END_ARGS },
 
497
                &DebuggerParser::executeTrap
 
498
        },
 
499
 
 
500
        {
 
501
                "trapread",
 
502
                "Trap read accesses to address",
 
503
                true,
 
504
                false,
 
505
                { kARG_WORD, kARG_END_ARGS },
 
506
                &DebuggerParser::executeTrapread
 
507
        },
 
508
 
 
509
        {
 
510
                "trapwrite",
 
511
                "Trap write accesses to address",
 
512
                true,
 
513
                false,
 
514
                { kARG_WORD, kARG_END_ARGS },
 
515
                &DebuggerParser::executeTrapwrite
 
516
        },
 
517
 
 
518
        {
 
519
                "undef",
 
520
                "Undefine label (if defined)",
 
521
                true,
 
522
                true,
 
523
                { kARG_LABEL, kARG_END_ARGS },
 
524
                &DebuggerParser::executeUndef
 
525
        },
 
526
 
 
527
        {
 
528
                "v",
 
529
                "Overflow Flag: set (to 0 or 1), or toggle (no arg)",
 
530
                false,
 
531
                true,
 
532
                { kARG_BOOL, kARG_END_ARGS },
 
533
                &DebuggerParser::executeV
 
534
        },
 
535
 
 
536
        {
 
537
                "watch",
 
538
                "Print contents of address before every prompt",
 
539
                true,
 
540
                false,
 
541
                { kARG_WORD, kARG_END_ARGS },
 
542
                &DebuggerParser::executeWatch
 
543
        },
 
544
 
 
545
        {
 
546
                "x",
 
547
                "Set X Register to value xx",
 
548
                true,
 
549
                true,
 
550
                { kARG_WORD, kARG_END_ARGS },
 
551
                &DebuggerParser::executeX
 
552
        },
 
553
 
 
554
        {
 
555
                "y",
 
556
                "Set Y Register to value xx",
 
557
                true,
 
558
                true,
 
559
                { kARG_WORD, kARG_END_ARGS },
 
560
                &DebuggerParser::executeY
 
561
        },
 
562
 
 
563
        {
 
564
                "z",
 
565
                "Zero Flag: set (to 0 or 1), or toggle (no arg)",
 
566
                false,
 
567
                true,
 
568
                { kARG_BOOL, kARG_END_ARGS },
 
569
                &DebuggerParser::executeZ
 
570
        },
 
571
 
 
572
        {
 
573
                "",
 
574
                "",
 
575
                false,
 
576
                false,
 
577
                { kARG_END_ARGS },
 
578
                NULL
 
579
        }
 
580
 
 
581
};
 
582
 
 
583
// Constants for argument processing
 
584
enum {
 
585
  kIN_COMMAND,
 
586
  kIN_SPACE,
 
587
  kIN_BRACE,
 
588
  kIN_ARG
 
589
};
 
590
 
 
591
DebuggerParser::DebuggerParser(Debugger* d)
 
592
        : debugger(d)
 
593
{
 
594
        done = false;
 
595
        defaultBase = kBASE_16;
 
596
}
 
597
 
 
598
DebuggerParser::~DebuggerParser() {
 
599
        args.clear();
 
600
        argStrings.clear();
 
601
        watches.clear();
 
602
}
 
603
 
 
604
int DebuggerParser::conv_hex_digit(char d) {
 
605
        if(d >= '0' && d <= '9')
 
606
                return d - '0';
 
607
        else if(d >= 'a' && d <= 'f')
 
608
                return d - 'a' + 10;
 
609
        else if(d >= 'A' && d <= 'F')
 
610
                return d - 'A' + 10;
 
611
        else return -1;
 
612
}
 
613
 
 
614
// Evaluate expression. Expressions always evaluate to a 16-bit value if
 
615
// they're valid, or -1 if they're not.
 
616
 
 
617
// decipher_arg may be called by the GUI as needed. It is also called
 
618
// internally by DebuggerParser::run()
 
619
int DebuggerParser::decipher_arg(const string &str) {
 
620
        bool derefByte=false, derefWord=false, lobyte=false, hibyte=false, bin=false, dec=false;
 
621
        int result;
 
622
        string arg = str;
 
623
 
 
624
        if(defaultBase == kBASE_2) {
 
625
                bin=true; dec=false;
 
626
        } else if(defaultBase == kBASE_10) {
 
627
                bin=false; dec=true;
 
628
        } else {
 
629
                bin=false; dec=false;
 
630
        }
 
631
 
 
632
        if(arg.substr(0, 1) == "*") {
 
633
                derefByte = true;
 
634
                arg.erase(0, 1);
 
635
        } else if(arg.substr(0, 1) == "@") {
 
636
                derefWord = true;
 
637
                arg.erase(0, 1);
 
638
        }
 
639
 
 
640
        if(arg.substr(0, 1) == "<") {
 
641
                lobyte = true;
 
642
                arg.erase(0, 1);
 
643
        } else if(arg.substr(0, 1) == ">") {
 
644
                hibyte = true;
 
645
                arg.erase(0, 1);
 
646
        }
 
647
 
 
648
        if(arg.substr(0, 1) == "%") {
 
649
                bin = true;
 
650
                dec = false;
 
651
                arg.erase(0, 1);
 
652
        } else if(arg.substr(0, 1) == "#") {
 
653
                dec = true;
 
654
                bin = false;
 
655
                arg.erase(0, 1);
 
656
        } else if(arg.substr(0, 1) == "$") {
 
657
                dec = false;
 
658
                bin = false;
 
659
                arg.erase(0, 1);
 
660
        }
 
661
 
 
662
        // sanity check mutually exclusive options:
 
663
        if(derefByte && derefWord) return -1;
 
664
        if(lobyte && hibyte) return -1;
 
665
        if(bin && dec) return -1;
 
666
 
 
667
        // Special cases (registers):
 
668
        CpuState& state = (CpuState&) debugger->cpuDebug().getState();
 
669
        if(arg == "a") result = state.A;
 
670
        else if(arg == "x") result = state.X;
 
671
        else if(arg == "y") result = state.Y;
 
672
        else if(arg == "p") result = state.PS;
 
673
        else if(arg == "s") result = state.SP;
 
674
        else if(arg == "pc" || arg == ".") result = state.PC;
 
675
        else { // Not a special, must be a regular arg: check for label first
 
676
                const char *a = arg.c_str();
 
677
                result = debugger->equateList->getAddress(arg);
 
678
 
 
679
                if(result < 0) { // if not label, must be a number
 
680
                        if(bin) { // treat as binary
 
681
                                result = 0;
 
682
                                while(*a != '\0') {
 
683
                                        result <<= 1;
 
684
                                        switch(*a++) {
 
685
                                                case '1':
 
686
                                                        result++;
 
687
                                                        break;
 
688
 
 
689
                                                case '0':
 
690
                                                        break;
 
691
 
 
692
                                                default:
 
693
                                                        return -1;
 
694
                                        }
 
695
                                }
 
696
                        } else if(dec) {
 
697
                                result = 0;
 
698
                                while(*a != '\0') {
 
699
                                        int digit = (*a++) - '0';
 
700
                                        if(digit < 0 || digit > 9)
 
701
                                                return -1;
 
702
 
 
703
                                        result = (result * 10) + digit;
 
704
                                }
 
705
                        } else { // must be hex.
 
706
                                result = 0;
 
707
                                while(*a != '\0') {
 
708
                                        int hex = conv_hex_digit(*a++);
 
709
                                        if(hex < 0)
 
710
                                                return -1;
 
711
 
 
712
                                        result = (result << 4) + hex;
 
713
                                }
 
714
                        }
 
715
                }
 
716
        }
 
717
 
 
718
        if(lobyte) result &= 0xff;
 
719
        else if(hibyte) result = (result >> 8) & 0xff;
 
720
 
 
721
        // dereference if we're supposed to:
 
722
        if(derefByte) result = debugger->peek(result);
 
723
        if(derefWord) result = debugger->dpeek(result);
 
724
 
 
725
        return result;
 
726
}
 
727
 
 
728
bool DebuggerParser::getArgs(const string& command) {
 
729
        int state = kIN_COMMAND;
 
730
        string curArg = "";
 
731
        verb = "";
 
732
        const char *c = command.c_str();
 
733
 
 
734
        argStrings.clear();
 
735
        args.clear();
 
736
 
 
737
        // cerr << "Parsing \"" << command << "\"" << endl;
 
738
 
 
739
        // First, pick apart string into space-separated tokens.
 
740
        // The first token is the command verb, the rest go in an array
 
741
        do {
 
742
                // cerr << "State " << state << ", *c '" << *c << "'" << endl;
 
743
                switch(state) {
 
744
                        case kIN_COMMAND:
 
745
                                if(*c == ' ')
 
746
                                        state = kIN_SPACE;
 
747
                                else
 
748
                                        verb += *c;
 
749
                                break;
 
750
 
 
751
                        case kIN_SPACE:
 
752
                                if(*c == '{')
 
753
                                        state = kIN_BRACE;
 
754
                                else if(*c != ' ') {
 
755
                                        state = kIN_ARG;
 
756
                                        curArg += *c;
 
757
                                }
 
758
                                break;
 
759
 
 
760
                        case kIN_BRACE:
 
761
                                if(*c == '}' || *c == '\0') {
 
762
                                        state = kIN_SPACE;
 
763
                                        argStrings.push_back(curArg);
 
764
                                        //      cerr << "{" << curArg << "}" << endl;
 
765
                                        curArg = "";
 
766
                                } else {
 
767
                                        curArg += *c;
 
768
                                }
 
769
                                break;
 
770
 
 
771
                        case kIN_ARG:
 
772
                                if(*c == ' ' || *c == '\0') {
 
773
                                        state = kIN_SPACE;
 
774
                                        argStrings.push_back(curArg);
 
775
                                        curArg = "";
 
776
                                } else {
 
777
                                        curArg += *c;
 
778
                                }
 
779
                                break;
 
780
                } // switch(state)
 
781
        } while(*c++ != '\0');
 
782
 
 
783
        argCount = argStrings.size();
 
784
 
 
785
        /*
 
786
        // Now decipher each argument, in turn.
 
787
        for(int i=0; i<argCount; i++) {
 
788
                int temp = decipher_arg(argStrings[i]);
 
789
                args.push_back(temp); // value maybe -1, if not expression argument
 
790
                                      // (validate_args will decide whether that's OK, not us.)
 
791
        }
 
792
        */
 
793
 
 
794
        for(int i=0; i<argCount; i++) {
 
795
                int err = YaccParser::parse(argStrings[i].c_str());
 
796
                if(err) {
 
797
                        args.push_back(-1);
 
798
                } else {
 
799
                        Expression *e = YaccParser::getResult();
 
800
                        args.push_back( e->evaluate() );
 
801
                        delete e;
 
802
                }
 
803
        }
 
804
 
 
805
        return true;
 
806
}
 
807
 
 
808
bool DebuggerParser::subStringMatch(const string& needle, const string& haystack) {
 
809
        const char *hs = haystack.c_str();
 
810
        const char *n = needle.c_str();
 
811
 
 
812
        if(STR_N_CASE_CMP(n, hs, strlen(n)) == 0)
 
813
                return true;
 
814
 
 
815
        return false;
 
816
}
 
817
 
 
818
string DebuggerParser::listBreaks() {
 
819
        char buf[255];
 
820
        int count = 0;
 
821
        string ret = "";
 
822
 
 
823
        for(unsigned int i=0; i<0x10000; i++) {
 
824
                if(debugger->breakPoints->isSet(i)) {
 
825
                        sprintf(buf, "%s ", debugger->equateList->getFormatted(i, 4));
 
826
                        ret += buf;
 
827
                        if(! (++count % 8) ) ret += "\n";
 
828
                }
 
829
        }
 
830
        /*
 
831
        if(count)
 
832
                return ret;
 
833
        else
 
834
                return "no breakpoints set";
 
835
                */
 
836
        if(count)
 
837
                ret = "breaks:\n" + ret;
 
838
 
 
839
        StringList conds = debugger->cpuDebug().m6502().getCondBreakNames();
 
840
        if(conds.size() > 0) {
 
841
                ret += "\nbreakifs:\n";
 
842
                for(unsigned int i=0; i<conds.size(); i++) {
 
843
                        ret += debugger->valueToString(i);
 
844
                        ret += ": ";
 
845
                        ret += conds[i];
 
846
                        if(i != (conds.size() - 1)) ret += "\n";
 
847
                }
 
848
        }
 
849
 
 
850
        if(ret == "")
 
851
                return "no breakpoints set";
 
852
        else
 
853
                return ret;
 
854
}
 
855
 
 
856
string DebuggerParser::listTraps() {
 
857
        int count = 0;
 
858
        string ret;
 
859
 
 
860
        for(unsigned int i=0; i<0x10000; i++) {
 
861
                if(debugger->readTrap(i) || debugger->writeTrap(i)) {
 
862
                        ret += trapStatus(i);
 
863
                        ret += "\n";
 
864
                        count++;
 
865
                }
 
866
        }
 
867
 
 
868
        if(count)
 
869
                return ret;
 
870
        else
 
871
                return "no traps set";
 
872
}
 
873
 
 
874
string DebuggerParser::disasm() {
 
875
        int start, lines = 20;
 
876
 
 
877
        if(argCount == 0) {
 
878
                start = debugger->cpuDebug().pc();
 
879
        } else if(argCount == 1) {
 
880
                start = args[0];
 
881
        } else if(argCount == 2) {
 
882
                start = args[0];
 
883
                lines = args[1];
 
884
        } else {
 
885
                return "wrong number of arguments";
 
886
        }
 
887
 
 
888
        return debugger->disassemble(start, lines);
 
889
}
 
890
 
 
891
string DebuggerParser::dump() {
 
892
        string ret;
 
893
        for(int i=0; i<8; i++) {
 
894
                int start = args[0] + i*16;
 
895
                ret += debugger->valueToString(start);
 
896
                ret += ": ";
 
897
                for(int j=0; j<16; j++) {
 
898
                        ret += debugger->valueToString( debugger->peek(start+j) );
 
899
                        ret += " ";
 
900
                        if(j == 7) ret += "- ";
 
901
                }
 
902
                if(i != 7) ret += "\n";
 
903
        }
 
904
        return ret;
 
905
}
 
906
 
 
907
string DebuggerParser::eval() {
 
908
        char buf[50];
 
909
        string ret;
 
910
        for(int i=0; i<argCount; i++) {
 
911
                string label = debugger->equates()->getLabel(args[i]);
 
912
                if(label != "") {
 
913
                        ret += label;
 
914
                        ret += ": ";
 
915
                }
 
916
                ret += "$";
 
917
                if(args[i] < 0x100) {
 
918
                        ret += Debugger::to_hex_8(args[i]);
 
919
                        ret += " %";
 
920
                        ret += Debugger::to_bin_8(args[i]);
 
921
                } else {
 
922
                        ret += Debugger::to_hex_16(args[i]);
 
923
                        ret += " %";
 
924
                        ret += Debugger::to_bin_16(args[i]);
 
925
                }
 
926
                sprintf(buf, " #%d", args[i]);
 
927
                ret += buf;
 
928
                if(i != argCount - 1) ret += "\n";
 
929
        }
 
930
        return ret;
 
931
}
 
932
 
 
933
string DebuggerParser::showWatches() {
 
934
        string ret;
 
935
        char buf[10];
 
936
 
 
937
        for(unsigned int i=0; i<watches.size(); i++) {
 
938
                if(watches[i] != "") {
 
939
                        // Clear the args, since we're going to pass them to eval()
 
940
                        argStrings.clear();
 
941
                        args.clear();
 
942
 
 
943
                        sprintf(buf, "%d", i+1);
 
944
                        argCount = 1;
 
945
                        argStrings.push_back(watches[i]);
 
946
                        args.push_back(decipher_arg(argStrings[0]));
 
947
                        if(args[0] < 0) {
 
948
                                ret += "BAD WATCH ";
 
949
                                ret += buf;
 
950
                                ret += ": " + argStrings[0] + "\n";
 
951
                        } else {
 
952
                                ret += " watch #";
 
953
                                ret += buf;
 
954
                                ret += " (" + argStrings[0] + ") -> " + eval() + "\n";
 
955
                        }
 
956
                }
 
957
        }
 
958
        return ret;
 
959
}
 
960
 
 
961
string DebuggerParser::addWatch(string watch) {
 
962
        watches.push_back(watch);
 
963
        return "Added watch";
 
964
}
 
965
 
 
966
void DebuggerParser::delAllWatches() {
 
967
        watches.clear();
 
968
}
 
969
 
 
970
string DebuggerParser::delWatch(int which) {
 
971
        which--;
 
972
        if(which < 0 || which >= (int)watches.size())
 
973
                return "no such watch";
 
974
        else
 
975
                watches.remove_at(which);
 
976
 
 
977
        return "removed watch";
 
978
}
 
979
 
 
980
string DebuggerParser::trapStatus(int addr) {
 
981
        string result;
 
982
        result += debugger->valueToString(addr);
 
983
        result += ": ";
 
984
        bool r = debugger->readTrap(addr);
 
985
        bool w = debugger->writeTrap(addr);
 
986
        if(r && w)
 
987
                result += "read|write";
 
988
        else if(r)
 
989
                result += "read";
 
990
        else if(w)
 
991
                result += "     write";
 
992
        else
 
993
                result += "   none   ";
 
994
 
 
995
        string l = debugger->equateList->getLabel(addr);
 
996
        if(l != "") {
 
997
                result += "  (";
 
998
                result += l;
 
999
                result += ")";
 
1000
        }
 
1001
 
 
1002
        return result;
 
1003
}
 
1004
 
 
1005
bool DebuggerParser::validateArgs(int cmd)
 
1006
{
 
1007
  // cerr << "entering validateArgs(" << cmd << ")" << endl;
 
1008
  bool required = commands[cmd].parmsRequired;
 
1009
  parameters *p = commands[cmd].parms;
 
1010
 
 
1011
  if(argCount == 0)
 
1012
  {
 
1013
    if(required)
 
1014
    {
 
1015
      commandResult = red("missing required argument(s)");
 
1016
      return false; // needed args. didn't get 'em.
 
1017
    }
 
1018
    else
 
1019
      return true;  // no args needed, no args got
 
1020
  }
 
1021
 
 
1022
  // Figure out how many arguments are required by the command
 
1023
  int count = 0, argRequiredCount = 0;
 
1024
  while(*p != kARG_END_ARGS && *p != kARG_MULTI_BYTE)
 
1025
  {
 
1026
    count++;
 
1027
    *p++;
 
1028
  }
 
1029
 
 
1030
  // Evil hack: some commands intentionally take multiple arguments
 
1031
  // In this case, the required number of arguments is unbounded
 
1032
  argRequiredCount = (*p == kARG_END_ARGS) ? count : argCount;
 
1033
 
 
1034
  p = commands[cmd].parms;
 
1035
  int curCount = 0;
 
1036
 
 
1037
  do {
 
1038
    if(curCount >= argCount)
 
1039
      break;
 
1040
 
 
1041
    int curArgInt     = args[curCount];
 
1042
    string& curArgStr = argStrings[curCount];
 
1043
 
 
1044
    switch(*p)
 
1045
    {
 
1046
      case kARG_WORD:
 
1047
        if(curArgInt < 0 || curArgInt > 0xffff)
 
1048
        {
 
1049
          commandResult = red("invalid word argument (must be 0-$ffff)");
 
1050
          return false;
 
1051
        }
 
1052
        break;
 
1053
 
 
1054
      case kARG_BYTE:
 
1055
        if(curArgInt < 0 || curArgInt > 0xff)
 
1056
        {
 
1057
          commandResult = red("invalid byte argument (must be 0-$ff)");
 
1058
          return false;
 
1059
        }
 
1060
        break;
 
1061
 
 
1062
      case kARG_BOOL:
 
1063
        if(curArgInt != 0 && curArgInt != 1)
 
1064
        {
 
1065
          commandResult = red("invalid boolean argument (must be 0 or 1)");
 
1066
          return false;
 
1067
        }
 
1068
        break;
 
1069
 
 
1070
      case kARG_BASE_SPCL:
 
1071
        if(curArgInt != 2 && curArgInt != 10 && curArgInt != 16
 
1072
           && curArgStr != "hex" && curArgStr != "dec" && curArgStr != "bin")
 
1073
        {
 
1074
          commandResult = red("invalid base (must be #2, #10, #16, \"bin\", \"dec\", or \"hex\")");
 
1075
          return false;
 
1076
        }
 
1077
        break;
 
1078
 
 
1079
      case kARG_LABEL:
 
1080
      case kARG_FILE:
 
1081
        break; // TODO: validate these (for now any string's allowed)
 
1082
 
 
1083
      case kARG_MULTI_BYTE:
 
1084
      case kARG_MULTI_WORD:
 
1085
        break; // FIXME: validate these (for now, any number's allowed)
 
1086
 
 
1087
      case kARG_END_ARGS:
 
1088
        break;
 
1089
    }
 
1090
    curCount++;
 
1091
    *p++;
 
1092
 
 
1093
  } while(*p != kARG_END_ARGS && curCount < argRequiredCount);
 
1094
 
 
1095
/*
 
1096
cerr << "curCount         = " << curCount << endl
 
1097
     << "argRequiredCount = " << argRequiredCount << endl
 
1098
     << "*p               = " << *p << endl << endl;
 
1099
*/
 
1100
 
 
1101
  if(curCount < argRequiredCount)
 
1102
  {
 
1103
    commandResult = red("missing required argument(s)");
 
1104
    return false;
 
1105
  }
 
1106
  else if(argCount > curCount)
 
1107
  {
 
1108
    commandResult = red("too many arguments");
 
1109
    return false;
 
1110
  }
 
1111
 
 
1112
  return true;
 
1113
}
 
1114
 
 
1115
// main entry point: PromptWidget calls this method.
 
1116
string DebuggerParser::run(const string& command) {
 
1117
 
 
1118
        /*
 
1119
                // this was our parser test code. Left for reference.
 
1120
        static Expression *lastExpression;
 
1121
 
 
1122
        // special case: parser testing
 
1123
        if(strncmp(command.c_str(), "expr ", 5) == 0) {
 
1124
                delete lastExpression;
 
1125
                commandResult = "parser test: status==";
 
1126
                int status = YaccParser::parse(command.c_str() + 5);
 
1127
                commandResult += debugger->valueToString(status);
 
1128
                commandResult += ", result==";
 
1129
                if(status == 0) {
 
1130
                        lastExpression = YaccParser::getResult();
 
1131
                        commandResult += debugger->valueToString(lastExpression->evaluate());
 
1132
                } else {
 
1133
                        //      delete lastExpression; // NO! lastExpression isn't valid (not 0 either)
 
1134
                                                  // It's the result of casting the last token
 
1135
                                                  // to Expression* (because of yacc's union).
 
1136
                                                  // As such, we can't and don't need to delete it
 
1137
                                                  // (However, it means yacc leaks memory on error)
 
1138
                        commandResult += "ERROR - ";
 
1139
                        commandResult += YaccParser::errorMessage();
 
1140
                }
 
1141
                return commandResult;
 
1142
        }
 
1143
 
 
1144
        if(command == "expr") {
 
1145
                if(lastExpression)
 
1146
                        commandResult = "result==" + debugger->valueToString(lastExpression->evaluate());
 
1147
                else
 
1148
                        commandResult = "no valid expr";
 
1149
                return commandResult;
 
1150
        }
 
1151
        */
 
1152
 
 
1153
        getArgs(command);
 
1154
#ifdef EXPR_REF_COUNT
 
1155
        extern int refCount;
 
1156
        cerr << "Expression count: " << refCount << endl;
 
1157
#endif
 
1158
        commandResult = "";
 
1159
 
 
1160
        int i=0;
 
1161
        do {
 
1162
                if( subStringMatch(verb, commands[i].cmdString.c_str()) ) {
 
1163
                        if( validateArgs(i) )
 
1164
                                CALL_METHOD(commands[i].executor);
 
1165
 
 
1166
                        if( commands[i].refreshRequired )
 
1167
                                debugger->myBaseDialog->loadConfig();
 
1168
 
 
1169
                        return commandResult;
 
1170
                }
 
1171
 
 
1172
        } while(commands[++i].cmdString != "");
 
1173
 
 
1174
        commandResult = "No such command (try \"help\")";
 
1175
        return commandResult;
 
1176
}
 
1177
 
 
1178
// completion-related stuff:
 
1179
int DebuggerParser::countCompletions(const char *in) {
 
1180
        int count = 0, i = 0;
 
1181
        completions = compPrefix = "";
 
1182
 
 
1183
        // cerr << "Attempting to complete \"" << in << "\"" << endl;
 
1184
        do {
 
1185
                const char *l = commands[i].cmdString.c_str();
 
1186
 
 
1187
                if(STR_N_CASE_CMP(l, in, strlen(in)) == 0) {
 
1188
                        if(compPrefix == "")
 
1189
                                compPrefix += l;
 
1190
                        else {
 
1191
                                int nonMatch = 0;
 
1192
                                const char *c = compPrefix.c_str();
 
1193
                                while(*c != '\0' && tolower(*c) == tolower(l[nonMatch])) {
 
1194
                                        c++;
 
1195
                                        nonMatch++;
 
1196
                                }
 
1197
                                compPrefix.erase(nonMatch, compPrefix.length());
 
1198
                                // cerr << "compPrefix==" << compPrefix << endl;
 
1199
                        }
 
1200
 
 
1201
                        if(count++) completions += "  ";
 
1202
                        completions += l;
 
1203
                }
 
1204
        } while(commands[++i].cmdString != "");
 
1205
 
 
1206
        // cerr << "Found " << count << " label(s):" << endl << completions << endl;
 
1207
        return count;
 
1208
}
 
1209
 
 
1210
const char *DebuggerParser::getCompletions() {
 
1211
        return completions.c_str();
 
1212
}
 
1213
 
 
1214
const char *DebuggerParser::getCompletionPrefix() {
 
1215
        return compPrefix.c_str();
 
1216
}
 
1217
 
 
1218
string DebuggerParser::exec(const string& cmd, bool verbose) {
 
1219
        string file = cmd;
 
1220
        string ret;
 
1221
        int count = 0;
 
1222
        char buffer[256]; // FIXME: static buffers suck
 
1223
 
 
1224
        if( file.find_last_of('.') == string::npos ) {
 
1225
                file += ".stella";
 
1226
        }
 
1227
 
 
1228
        ifstream in(file.c_str());
 
1229
        if(!in.is_open())
 
1230
                return red("file \"" + file + "\" not found.");
 
1231
 
 
1232
        while( !in.eof() ) {
 
1233
                if(!in.getline(buffer, 255))
 
1234
                        break;
 
1235
 
 
1236
                count++;
 
1237
                if(verbose) {
 
1238
                        ret += "exec> ";
 
1239
                        ret += buffer;
 
1240
                        ret += "\n";
 
1241
                        ret += run(buffer);
 
1242
                        ret += "\n";
 
1243
                }
 
1244
        }
 
1245
        ret += "Executed ";
 
1246
        ret += debugger->valueToString(count);
 
1247
        ret += " commands from \"";
 
1248
        ret += file;
 
1249
        ret += "\"\n";
 
1250
        return ret;
 
1251
}
 
1252
 
 
1253
bool DebuggerParser::saveScriptFile(string file) {
 
1254
        if( file.find_last_of('.') == string::npos ) {
 
1255
                file += ".stella";
 
1256
        }
 
1257
 
 
1258
        ofstream out(file.c_str());
 
1259
 
 
1260
        FunctionDefMap funcs = debugger->getFunctionDefMap();
 
1261
        for(FunctionDefMap::const_iterator i = funcs.begin(); i != funcs.end(); ++i)
 
1262
                out << "function " << i->first << " { " << i->second << " }" << endl;
 
1263
 
 
1264
        for(unsigned int i=0; i<watches.size(); i++)
 
1265
                out << "watch " << watches[i] << endl;
 
1266
 
 
1267
        for(unsigned int i=0; i<0x10000; i++)
 
1268
                if(debugger->breakPoint(i))
 
1269
                        out << "break #" << i << endl;
 
1270
 
 
1271
        for(unsigned int i=0; i<0x10000; i++) {
 
1272
                bool r = debugger->readTrap(i);
 
1273
                bool w = debugger->writeTrap(i);
 
1274
 
 
1275
                if(r && w)
 
1276
                        out << "trap #" << i << endl;
 
1277
                else if(r)
 
1278
                        out << "trapread #" << i << endl;
 
1279
                else if(w)
 
1280
                        out << "trapwrite #" << i << endl;
 
1281
        }
 
1282
 
 
1283
        StringList conds = debugger->cpuDebug().m6502().getCondBreakNames();
 
1284
        for(unsigned int i=0; i<conds.size(); i++)
 
1285
                out << "breakif {" << conds[i] << "}" << endl;
 
1286
 
 
1287
        bool ok = out.good();
 
1288
        out.close();
 
1289
        return ok;
 
1290
}
 
1291
 
 
1292
////// executor methods for commands[] array. All are void, no args.
 
1293
 
 
1294
// "a"
 
1295
void DebuggerParser::executeA() {
 
1296
        debugger->cpuDebug().setA((uInt8)args[0]);
 
1297
}
 
1298
 
 
1299
// "bank"
 
1300
void DebuggerParser::executeBank() {
 
1301
        int banks = debugger->bankCount();
 
1302
        if(argCount == 0) {
 
1303
                commandResult += debugger->getCartType();
 
1304
                commandResult += ": ";
 
1305
                if(banks < 2)
 
1306
                        commandResult += red("bankswitching not supported by this cartridge");
 
1307
                else {
 
1308
                        commandResult += debugger->valueToString(debugger->getBank());
 
1309
                        commandResult += "/";
 
1310
                        commandResult += debugger->valueToString(banks);
 
1311
                }
 
1312
        } else {
 
1313
                if(args[0] >= banks) {
 
1314
                        commandResult += red("invalid bank number (must be 0 to ");
 
1315
                        commandResult += debugger->valueToString(banks - 1);
 
1316
                        commandResult += ")";
 
1317
                } else if(debugger->setBank(args[0])) {
 
1318
                        commandResult += "switched bank OK";
 
1319
                } else {
 
1320
                        commandResult += red("unknown error switching banks");
 
1321
                }
 
1322
        }
 
1323
}
 
1324
 
 
1325
// "base"
 
1326
void DebuggerParser::executeBase() {
 
1327
        if(args[0] == 2 || argStrings[0] == "bin")
 
1328
                setBase(kBASE_2);
 
1329
        else if(args[0] == 10 || argStrings[0] == "dec")
 
1330
                setBase(kBASE_10);
 
1331
        else if(args[0] == 16 || argStrings[0] == "hex")
 
1332
                setBase(kBASE_16);
 
1333
 
 
1334
        commandResult = "default base set to ";
 
1335
        switch(defaultBase) {
 
1336
                case kBASE_2:
 
1337
                        commandResult += "#2/bin";
 
1338
                        break;
 
1339
 
 
1340
                case kBASE_10:
 
1341
                        commandResult += "#10/dec";
 
1342
                        break;
 
1343
 
 
1344
                case kBASE_16:
 
1345
                        commandResult += "#16/hex";
 
1346
                        break;
 
1347
 
 
1348
                default:
 
1349
                        commandResult += red("UNKNOWN");
 
1350
                        break;
 
1351
        }
 
1352
}
 
1353
 
 
1354
// "break"
 
1355
void DebuggerParser::executeBreak() {
 
1356
        int bp;
 
1357
        if(argCount == 0)
 
1358
                bp = debugger->cpuDebug().pc();
 
1359
        else
 
1360
                bp = args[0];
 
1361
        debugger->toggleBreakPoint(bp);
 
1362
        debugger->myRom->invalidate();
 
1363
 
 
1364
        if(debugger->breakPoint(bp))
 
1365
                commandResult = "Set";
 
1366
        else
 
1367
                commandResult = "Cleared";
 
1368
 
 
1369
        commandResult += " breakpoint at ";
 
1370
        commandResult += debugger->valueToString(bp);
 
1371
}
 
1372
 
 
1373
// "breakif"
 
1374
void DebuggerParser::executeBreakif() {
 
1375
        int res = YaccParser::parse(argStrings[0].c_str());
 
1376
        if(res == 0) {
 
1377
                // I hate this().method().chaining().crap()
 
1378
                unsigned int ret = debugger->cpuDebug().m6502().addCondBreak(
 
1379
                                YaccParser::getResult(), argStrings[0] );
 
1380
                commandResult = "Added breakif ";
 
1381
                commandResult += debugger->valueToString(ret);
 
1382
        } else {
 
1383
                commandResult = red("invalid expression");
 
1384
        }
 
1385
}
 
1386
 
 
1387
// "c"
 
1388
void DebuggerParser::executeC() {
 
1389
        if(argCount == 0)
 
1390
                debugger->cpuDebug().toggleC();
 
1391
        else if(argCount == 1)
 
1392
                debugger->cpuDebug().setC(args[0]);
 
1393
}
 
1394
 
 
1395
#ifdef CHEATCODE_SUPPORT
 
1396
// "cheat"
 
1397
// (see Stella manual for different cheat types)
 
1398
void DebuggerParser::executeCheat() {
 
1399
        if(argCount == 0) {
 
1400
                commandResult = red("Missing cheat code");
 
1401
                return;
 
1402
        }
 
1403
 
 
1404
        for(int arg = 0; arg < argCount; arg++) {
 
1405
                string& cheat = argStrings[arg];
 
1406
                const Cheat* c = debugger->getOSystem()->cheat().add("DBG", cheat);
 
1407
                if(c && c->enabled()) {
 
1408
                        commandResult = "Cheat code " + cheat + " enabled\n";
 
1409
                } else {
 
1410
                        commandResult = red("Invalid cheat code " + cheat + "\n");
 
1411
                }
 
1412
        }
 
1413
}
 
1414
#endif
 
1415
 
 
1416
// "clearbreaks"
 
1417
void DebuggerParser::executeClearbreaks() {
 
1418
        debugger->clearAllBreakPoints();
 
1419
        debugger->cpuDebug().m6502().clearCondBreaks();
 
1420
        commandResult = "all breakpoints cleared";
 
1421
}
 
1422
 
 
1423
// "cleartraps"
 
1424
void DebuggerParser::executeCleartraps() {
 
1425
        debugger->clearAllTraps();
 
1426
        commandResult = "all traps cleared";
 
1427
}
 
1428
 
 
1429
// "clearwatches"
 
1430
void DebuggerParser::executeClearwatches() {
 
1431
        delAllWatches();
 
1432
        commandResult = "all watches cleared";
 
1433
}
 
1434
 
 
1435
// "colortest"
 
1436
void DebuggerParser::executeColortest() {
 
1437
        commandResult = "test color: ";
 
1438
        commandResult += char((args[0]>>1) | 0x80);
 
1439
        commandResult += inverse("        ");
 
1440
}
 
1441
 
 
1442
// "d"
 
1443
void DebuggerParser::executeD() {
 
1444
        if(argCount == 0)
 
1445
                debugger->cpuDebug().toggleD();
 
1446
        else if(argCount == 1)
 
1447
                debugger->cpuDebug().setD(args[0]);
 
1448
}
 
1449
 
 
1450
// "define"
 
1451
void DebuggerParser::executeDefine() {
 
1452
        // TODO: check if label already defined?
 
1453
        debugger->addLabel(argStrings[0], args[1]);
 
1454
        debugger->myRom->invalidate();
 
1455
        commandResult = "label " + argStrings[0] + " defined as " + debugger->valueToString(args[1]);
 
1456
}
 
1457
 
 
1458
// "delbreakif"
 
1459
void DebuggerParser::executeDelbreakif() {
 
1460
        debugger->cpuDebug().m6502().delCondBreak(args[0]);
 
1461
}
 
1462
 
 
1463
// "delwatch"
 
1464
void DebuggerParser::executeDelwatch() {
 
1465
        commandResult = delWatch(args[0]);
 
1466
}
 
1467
 
 
1468
// "disasm"
 
1469
void DebuggerParser::executeDisasm() {
 
1470
        commandResult = disasm();
 
1471
}
 
1472
 
 
1473
// "dump"
 
1474
void DebuggerParser::executeDump() {
 
1475
        commandResult = dump();
 
1476
}
 
1477
 
 
1478
// "exec"
 
1479
void DebuggerParser::executeExec() {
 
1480
        commandResult = exec(argStrings[0]);
 
1481
}
 
1482
 
 
1483
// "height"
 
1484
void DebuggerParser::executeHeight() {
 
1485
  int height = debugger->setHeight(args[0]);
 
1486
  commandResult = "height set to " + debugger->valueToString(height, kBASE_10) +
 
1487
                  "\nExit debugger and reload ROM to take effect";
 
1488
}
 
1489
 
 
1490
// "help"
 
1491
void DebuggerParser::executeHelp() {
 
1492
        static char buf[256];
 
1493
        int i = 0;
 
1494
        do {
 
1495
                sprintf(buf, "%13s - %s\n",
 
1496
                        commands[i].cmdString.c_str(),
 
1497
                        commands[i].description.c_str());
 
1498
 
 
1499
                commandResult += buf;
 
1500
        } while(commands[++i].cmdString != "");
 
1501
 
 
1502
        commandResult += "\nBuilt-in functions:\n";
 
1503
        commandResult += debugger->builtinHelp();
 
1504
}
 
1505
 
 
1506
// "frame"
 
1507
void DebuggerParser::executeFrame() {
 
1508
        int count = 1;
 
1509
        if(argCount != 0) count = args[0];
 
1510
        debugger->nextFrame(count);
 
1511
        commandResult = "advanced ";
 
1512
        commandResult += debugger->valueToString(count);
 
1513
        commandResult += " frame";
 
1514
        if(count != 1) commandResult += "s";
 
1515
}
 
1516
 
 
1517
// "function"
 
1518
void DebuggerParser::executeFunction() {
 
1519
        if(args[0] >= 0) {
 
1520
                commandResult = red("name already in use");
 
1521
                return;
 
1522
        }
 
1523
 
 
1524
        int res = YaccParser::parse(argStrings[1].c_str());
 
1525
        if(res == 0) {
 
1526
                debugger->addFunction(argStrings[0], argStrings[1], YaccParser::getResult());
 
1527
                commandResult = "Added function " + argStrings[0];
 
1528
        } else {
 
1529
                commandResult = red("invalid expression");
 
1530
        }
 
1531
}
 
1532
 
 
1533
// "list"
 
1534
void DebuggerParser::executeList() {
 
1535
        for(int i=args[0] - 2; i<args[0] + 3; i++)
 
1536
                commandResult += debugger->getSourceLines(i);
 
1537
}
 
1538
 
 
1539
// "listbreaks"
 
1540
void DebuggerParser::executeListbreaks() {
 
1541
        commandResult = listBreaks();
 
1542
}
 
1543
 
 
1544
// "listtraps"
 
1545
void DebuggerParser::executeListtraps() {
 
1546
        commandResult = listTraps();
 
1547
}
 
1548
 
 
1549
// "listwatches"
 
1550
void DebuggerParser::executeListwatches() {
 
1551
        // commandResult = listWatches();
 
1552
        commandResult = red("command not yet implemented (sorry)");
 
1553
}
 
1554
 
 
1555
// "loadstate"
 
1556
void DebuggerParser::executeLoadstate() {
 
1557
        if(args[0] >= 0 && args[0] <= 9) {
 
1558
                debugger->loadState(args[0]);
 
1559
                commandResult = "state loaded";
 
1560
        } else {
 
1561
                commandResult = red("invalid slot (must be 0-9)");
 
1562
        }
 
1563
}
 
1564
 
 
1565
// "loadlist"
 
1566
void DebuggerParser::executeLoadlist() {
 
1567
        commandResult = debugger->loadListFile(argStrings[0]);
 
1568
}
 
1569
 
 
1570
// "loadsym"
 
1571
void DebuggerParser::executeLoadsym() {
 
1572
        commandResult = debugger->equateList->loadFile(argStrings[0]);
 
1573
        debugger->myRom->invalidate();
 
1574
}
 
1575
 
 
1576
// "n"
 
1577
void DebuggerParser::executeN() {
 
1578
        if(argCount == 0)
 
1579
                debugger->cpuDebug().toggleN();
 
1580
        else if(argCount == 1)
 
1581
                debugger->cpuDebug().setN(args[0]);
 
1582
}
 
1583
 
 
1584
// "pc"
 
1585
void DebuggerParser::executePc() {
 
1586
        debugger->cpuDebug().setPC(args[0]);
 
1587
}
 
1588
 
 
1589
// "print"
 
1590
void DebuggerParser::executePrint() {
 
1591
        commandResult = eval();
 
1592
}
 
1593
 
 
1594
// "ram"
 
1595
void DebuggerParser::executeRam() {
 
1596
        if(argCount == 0)
 
1597
                commandResult = debugger->dumpRAM();
 
1598
        else
 
1599
                commandResult = debugger->setRAM(args);
 
1600
}
 
1601
 
 
1602
// "reload"
 
1603
void DebuggerParser::executeReload() {
 
1604
        debugger->reloadROM();
 
1605
        debugger->start();
 
1606
        commandResult = "reloaded";
 
1607
}
 
1608
 
 
1609
// "reset"
 
1610
void DebuggerParser::executeReset() {
 
1611
        debugger->reset();
 
1612
        commandResult = "reset CPU";
 
1613
}
 
1614
 
 
1615
// "riot"
 
1616
void DebuggerParser::executeRiot() {
 
1617
        commandResult = debugger->riotState();
 
1618
}
 
1619
 
 
1620
// "rom"
 
1621
void DebuggerParser::executeRom() {
 
1622
        int addr = args[0];
 
1623
        for(int i=1; i<argCount; i++) {
 
1624
                if( !(debugger->patchROM(addr++, args[i])) ) {
 
1625
                        commandResult = red("patching ROM unsupported for this cart type");
 
1626
                        return;
 
1627
                }
 
1628
        }
 
1629
 
 
1630
        // Normally the run() method calls loadConfig() on the debugger,
 
1631
        // which results in all child widgets being redrawn.
 
1632
        // The RomWidget is a special case, since we don't want to re-disassemble
 
1633
        // any more than necessary.  So we only do it by calling the following
 
1634
        // method ...
 
1635
        debugger->myRom->invalidate();
 
1636
 
 
1637
        commandResult = "changed ";
 
1638
        commandResult += debugger->valueToString( args.size() - 1 );
 
1639
        commandResult += " location(s)";
 
1640
}
 
1641
 
 
1642
// "run"
 
1643
void DebuggerParser::executeRun() {
 
1644
        debugger->saveOldState();
 
1645
        debugger->quit();
 
1646
        commandResult = "exiting debugger";
 
1647
}
 
1648
 
 
1649
// "runto"
 
1650
void DebuggerParser::executeRunTo() {
 
1651
        bool done = false;
 
1652
        int cycles = 0, count = 0;
 
1653
 
 
1654
        do {
 
1655
                cycles += debugger->step();
 
1656
                if(++count % 100 == 0)
 
1657
                        debugger->prompt()->putchar('.');
 
1658
                string next = debugger->disassemble(debugger->cpuDebug().pc(), 1);
 
1659
                done = (next.find(argStrings[0]) != string::npos);
 
1660
        } while(!done);
 
1661
 
 
1662
        commandResult = "executed ";
 
1663
        commandResult += debugger->valueToString(cycles);
 
1664
        commandResult += " cycles";
 
1665
}
 
1666
 
 
1667
// "s"
 
1668
void DebuggerParser::executeS() {
 
1669
        debugger->cpuDebug().setSP((uInt8)args[0]);
 
1670
}
 
1671
 
 
1672
// "save"
 
1673
void DebuggerParser::executeSave() {
 
1674
        if(saveScriptFile(argStrings[0]))
 
1675
                commandResult = "saved script to file " + argStrings[0];
 
1676
        else
 
1677
                commandResult = red("I/O error");
 
1678
}
 
1679
 
 
1680
// "saverom"
 
1681
void DebuggerParser::executeSaverom() {
 
1682
  if(debugger->saveROM(argStrings[0]))
 
1683
    commandResult = "saved ROM as " + argStrings[0];
 
1684
  else
 
1685
    commandResult = red("failed to save ROM");
 
1686
}
 
1687
 
 
1688
// "saveses"
 
1689
void DebuggerParser::executeSaveses() {
 
1690
        if(debugger->prompt()->saveBuffer(argStrings[0]))
 
1691
                commandResult = "saved session to file " + argStrings[0];
 
1692
        else
 
1693
                commandResult = red("I/O error");
 
1694
}
 
1695
 
 
1696
// "savestate"
 
1697
void DebuggerParser::executeSavestate() {
 
1698
        if(args[0] >= 0 && args[0] <= 9) {
 
1699
                debugger->saveState(args[0]);
 
1700
                commandResult = "state saved";
 
1701
        } else {
 
1702
                commandResult = red("invalid slot (must be 0-9)");
 
1703
        }
 
1704
}
 
1705
 
 
1706
// "savesym"
 
1707
void DebuggerParser::executeSavesym() {
 
1708
        if(debugger->equateList->saveFile(argStrings[0]))
 
1709
                commandResult = "saved symbols to file " + argStrings[0];
 
1710
        else
 
1711
                commandResult = red("I/O error");
 
1712
}
 
1713
 
 
1714
// "scanline"
 
1715
void DebuggerParser::executeScanline() {
 
1716
        int count = 1;
 
1717
        if(argCount != 0) count = args[0];
 
1718
        debugger->nextScanline(count);
 
1719
        commandResult = "advanced ";
 
1720
        commandResult += debugger->valueToString(count);
 
1721
        commandResult += " scanline";
 
1722
        if(count != 1) commandResult += "s";
 
1723
}
 
1724
 
 
1725
// "step"
 
1726
void DebuggerParser::executeStep() {
 
1727
        int cycles = debugger->step();
 
1728
        commandResult = "executed ";
 
1729
        commandResult += debugger->valueToString(cycles);
 
1730
        commandResult += " cycles";
 
1731
}
 
1732
 
 
1733
// "tia"
 
1734
void DebuggerParser::executeTia() {
 
1735
        commandResult = debugger->dumpTIA();
 
1736
}
 
1737
 
 
1738
// "trace"
 
1739
void DebuggerParser::executeTrace() {
 
1740
        int cycles = debugger->trace();
 
1741
        commandResult = "executed ";
 
1742
        commandResult += debugger->valueToString(cycles);
 
1743
        commandResult += " cycles";
 
1744
}
 
1745
 
 
1746
// "trap"
 
1747
void DebuggerParser::executeTrap() {
 
1748
        debugger->toggleReadTrap(args[0]);
 
1749
        debugger->toggleWriteTrap(args[0]);
 
1750
        commandResult = trapStatus(args[0]);
 
1751
}
 
1752
 
 
1753
// "trapread"
 
1754
void DebuggerParser::executeTrapread() {
 
1755
        debugger->toggleReadTrap(args[0]);
 
1756
        commandResult = trapStatus(args[0]);
 
1757
}
 
1758
 
 
1759
// "trapwrite"
 
1760
void DebuggerParser::executeTrapwrite() {
 
1761
        debugger->toggleWriteTrap(args[0]);
 
1762
        commandResult = trapStatus(args[0]);
 
1763
}
 
1764
 
 
1765
// "undef"
 
1766
void DebuggerParser::executeUndef() {
 
1767
        if(debugger->equateList->undefine(argStrings[0]))
 
1768
        {
 
1769
                debugger->myRom->invalidate();
 
1770
                commandResult = argStrings[0] + " now undefined";
 
1771
        }
 
1772
        else
 
1773
                commandResult = red("no such label");
 
1774
}
 
1775
 
 
1776
// "v"
 
1777
void DebuggerParser::executeV() {
 
1778
        if(argCount == 0)
 
1779
                debugger->cpuDebug().toggleV();
 
1780
        else if(argCount == 1)
 
1781
                debugger->cpuDebug().setV(args[0]);
 
1782
}
 
1783
 
 
1784
// "watch"
 
1785
void DebuggerParser::executeWatch() {
 
1786
        addWatch(argStrings[0]);
 
1787
        commandResult = "added watch \"" + argStrings[0] + "\"";
 
1788
}
 
1789
 
 
1790
// "x"
 
1791
void DebuggerParser::executeX() {
 
1792
        debugger->cpuDebug().setX((uInt8)args[0]);
 
1793
}
 
1794
 
 
1795
// "y"
 
1796
void DebuggerParser::executeY() {
 
1797
        debugger->cpuDebug().setY((uInt8)args[0]);
 
1798
}
 
1799
 
 
1800
// "z"
 
1801
void DebuggerParser::executeZ() {
 
1802
        if(argCount == 0)
 
1803
                debugger->cpuDebug().toggleZ();
 
1804
        else if(argCount == 1)
 
1805
                debugger->cpuDebug().setZ(args[0]);
 
1806
}
 
1807