Several changes to make entering commands at the debugger prompt

case-insensive.  Currently supported are all commands and
pseudo-registers.  Equates/labels and user-defined functions are
still a WIP, since they're stored in various hashtables accessible
by name, which is still a case-sensitive operation.  In general,
tab completion is mostly case-insensitive.

Changed the delimiter for surrounding lines with spaces from curly
braces ({}) to the apostrophe (').


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2115 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2010-08-23 16:19:17 +00:00
parent bc28a2408d
commit d664beb45d
5 changed files with 67 additions and 53 deletions

View File

@ -27,7 +27,7 @@ feature that no other 2600 debugger has; it's <b>completely</b> cross-platform.<
breakpoints as you want.</li>
<li>Conditional breakpoints - Break running program when some arbitrary
condition is true (e.g. "breakif {a == $7f &amp;&amp; c}" will break when the Accumulator value is $7f and the Carry flag is true, no matter where
condition is true (e.g. "breakif &apos;a == $7f &amp;&amp; c&apos;" will break when the Accumulator value is $7f and the Carry flag is true, no matter where
in the program this happens). Unlike the cond breaks in PCAE, Stella's
are *fast*: the emulation will run at full speed unless you use lots
of breakif's at the same time, or have a slow CPU.</li>
@ -387,9 +387,9 @@ we want to apply the ! to the result of the &amp;, not just the first term
<p>"breakif !(*SWCHB&amp;1)" will do the job for us. However, it's an ugly mess
of letters, numbers, and punctuation. We can do a little better:</p>
<p>"breakif { !(*SWCHB &amp; 1 ) }" is a lot more readable, isn't it? If
<p>"breakif &apos; !(*SWCHB &amp; 1 ) &apos;" is a lot more readable, isn't it? If
you're going to use readable expressions with spaces in them,
enclose the entire expression in curly braces {}.</p>
enclose the entire expression in single quotes.</p>
<p>Remember that Stella only checks for input once per frame, so a break
condition that depends on input (like SWCHB) will always happen at the
@ -415,7 +415,7 @@ if we wanted to use it again.</p>
"breakif function_name":</p>
<pre>
function gameReset { !(*SWCHB &amp; 1 ) }
function gameReset &apos; !(*SWCHB &amp; 1 ) &apos;
breakif gameReset
</pre>
@ -426,7 +426,7 @@ if the Game Select switch is pressed. We want to break when the user
presses both Select and Reset:</p>
<pre>
breakif { gameReset &amp;&amp; gameSelect }
breakif &apos; gameReset &amp;&amp; gameSelect &apos;
</pre>
<p>User-defined functions appear in "listfunctions", which shows the label
@ -464,7 +464,7 @@ of this file will depend on the version of Stella, as follows:</p>
</tr>
</table>
<p>Note that these '.stella' script files are only accessed if you enter
the debugger at least one during a program run. This means you can create
the debugger at least once during a program run. This means you can create
these files, and not worry about slowing down emulation unless you're
actively using the debugger.</p>
@ -491,8 +491,8 @@ Stella debugger.</p>
<tr><td> _joy1up</td><td> !(*SWCHA &amp; $01)</td><td> Right joystick moved up</td></tr>
<tr><td> _joy1down</td><td> !(*SWCHA &amp; $02)</td><td> Right joystick moved down</td></tr>
<tr><td> _joy1button</td><td> !(*INPT5 &amp; $80)</td><td> Right joystick button pressed</td></tr>
<tr><td> _select</td><td> !(*SWCHB &amp; $01)</td><td> Game Select pressed</td></tr>
<tr><td> _reset</td><td> !(*SWCHB &amp; $02)</td><td> Game Reset pressed</td></tr>
<tr><td> _select</td><td> !(*SWCHB &amp; $02)</td><td> Game Select pressed</td></tr>
<tr><td> _reset</td><td> !(*SWCHB &amp; $01)</td><td> Game Reset pressed</td></tr>
<tr><td> _color</td><td> *SWCHB &amp; $08</td><td> Color/BW set to Color</td></tr>
<tr><td> _bw</td><td> !(*SWCHB &amp; $08)</td><td> Color/BW set to BW</td></tr>
<tr><td> _diff0b</td><td> !(*SWCHB &amp; $40)</td><td> Left difficulty set to B (easy)</td></tr>
@ -534,7 +534,7 @@ beginning of the 64th scanline.</p>
(non-bankswitched) ROMs, it will always contain 0. One useful use is:</p>
<pre>
breakif { pc==myLabel &amp;&amp; _bank==1 }
breakif &apos; pc==myLabel &amp;&amp; _bank==1 &apos;
</pre>
<p>This is similar to setting a regular breakpoint, but it will only trigger

View File

@ -114,6 +114,8 @@ template<typename T> inline void BSPF_swap(T& a, T& b) { T tmp = a; a = b; b = t
template<typename T> inline T BSPF_abs (T x) { return (x>=0) ? x : -x; }
template<typename T> inline T BSPF_min (T a, T b) { return (a<b) ? a : b; }
template<typename T> inline T BSPF_max (T a, T b) { return (a>b) ? a : b; }
// Test whether two strings are equal (case insensitive)
inline bool BSPF_equalsIgnoreCase(const string& s1, const string& s2)
{
return BSPF_strcasecmp(s1.c_str(), s2.c_str()) == 0;
@ -123,10 +125,22 @@ inline bool BSPF_equalsIgnoreCase(const char* s1, const char* s2)
return BSPF_strcasecmp(s1, s2) == 0;
}
// Test whether the first string starts with the second one (case insensitive)
inline bool BSPF_startsWithIgnoreCase(const string& s1, const string& s2)
{
return BSPF_strncasecmp(s1.c_str(), s2.c_str(), s2.length()) == 0;
}
inline bool BSPF_startsWithIgnoreCase(const char* s1, const char* s2)
{
return BSPF_strncasecmp(s1, s2, strlen(s2)) == 0;
}
// Test whether two characters are equal (case insensitive)
static bool BSPF_equalsIgnoreCaseChar(char ch1, char ch2)
{
return toupper((unsigned char)ch1) == toupper((unsigned char)ch2);
}
// Find location (if any) of the second string within the first
inline size_t BSPF_findIgnoreCase(const string& s1, const string& s2)
{
string::const_iterator pos = std::search(s1.begin(), s1.end(),

View File

@ -108,7 +108,7 @@ string DebuggerParser::run(const string& command)
for(int i = 0; i < kNumCommands; ++i)
{
if(verb == commands[i].cmdString)
if(BSPF_equalsIgnoreCase(verb, commands[i].cmdString))
{
if(validateArgs(i))
CALL_METHOD(commands[i].executor);
@ -159,9 +159,8 @@ void DebuggerParser::getCompletions(const char* in, StringList& completions) con
// cerr << "Attempting to complete \"" << in << "\"" << endl;
for(int i = 0; i < kNumCommands; ++i)
{
const char* l = commands[i].cmdString.c_str();
if(BSPF_strncasecmp(l, in, strlen(in)) == 0)
completions.push_back(l);
if(BSPF_startsWithIgnoreCase(commands[i].cmdString.c_str(), in))
completions.push_back(commands[i].cmdString);
}
}
@ -341,7 +340,7 @@ bool DebuggerParser::getArgs(const string& command, string& verb)
verb += c;
break;
case kIN_SPACE:
if(c == '{')
if(c == '\'')
state = kIN_BRACE;
else if(c != ' ') {
state = kIN_ARG;
@ -349,7 +348,7 @@ bool DebuggerParser::getArgs(const string& command, string& verb)
}
break;
case kIN_BRACE:
if(c == '}') {
if(c == '\'') {
state = kIN_SPACE;
argStrings.push_back(curArg);
// cerr << "{" << curArg << "}" << endl;

View File

@ -200,14 +200,14 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
int len = _promptEndPos - _promptStartPos;
if(len > 256) len = 256;
int lastDelimPos = -1;
int lastDelimPos = -1;
char delimiter = '\0';
char str[256];
for (i = 0; i < len; i++)
{
str[i] = buffer(_promptStartPos + i) & 0x7f;
if(strchr("*@<> ", str[i]) != NULL )
if(strchr("\'*@<> ", str[i]) != NULL )
{
lastDelimPos = i;
delimiter = str[i];
@ -885,7 +885,7 @@ string PromptWidget::getCompletionPrefix(const StringList& completions, string p
const string& s = completions[i];
if(s.length() < prefix.length())
return prefix; // current prefix is the best we're going to get
else if(s.compare(0, prefix.length(), prefix) != 0)
else if(!BSPF_startsWithIgnoreCase(s, prefix))
{
prefix.erase(prefix.length()-1);
return prefix;

View File

@ -15,9 +15,6 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
//============================================================================
//#include "YaccParser.hxx"
@ -81,23 +78,27 @@ int parse(const char *in)
}
/* hand-rolled lexer. Hopefully faster than flex... */
inline bool is_base_prefix(char x) { return ( (x=='\\' || x=='$' || x=='#') ); }
inline bool is_identifier(char x) {
return ( (x>='0' && x<='9') ||
(x>='a' && x<='z') ||
(x>='A' && x<='Z') ||
x=='.' || x=='_' );
inline bool is_base_prefix(char x)
{
return ( (x=='\\' || x=='$' || x=='#') );
}
inline bool is_identifier(char x)
{
return ( (x>='0' && x<='9') ||
(x>='a' && x<='z') ||
(x>='A' && x<='Z') ||
x=='.' || x=='_' );
}
inline bool is_operator(char x) {
inline bool is_operator(char x)
{
return ( (x=='+' || x=='-' || x=='*' ||
x=='/' || x=='<' || x=='>' ||
x=='|' || x=='&' || x=='^' ||
x=='!' || x=='~' || x=='(' ||
x==')' || x=='=' || x=='%' ||
x=='[' || x==']' ) );
x=='/' || x=='<' || x=='>' ||
x=='|' || x=='&' || x=='^' ||
x=='!' || x=='~' || x=='(' ||
x==')' || x=='=' || x=='%' ||
x=='[' || x==']' ) );
}
// const_to_int converts a string into a number, in either the
@ -171,29 +172,29 @@ int const_to_int(char *c) {
// special methods that get e.g. CPU registers
CPUDEBUG_INT_METHOD getCpuSpecial(char *c)
{
if(strcmp(c, "a") == 0)
if(BSPF_equalsIgnoreCase(c, "a"))
return &CpuDebug::a;
else if(strcmp(c, "x") == 0)
else if(BSPF_equalsIgnoreCase(c, "x"))
return &CpuDebug::x;
else if(strcmp(c, "y") == 0)
else if(BSPF_equalsIgnoreCase(c, "y"))
return &CpuDebug::y;
else if(strcmp(c, "pc") == 0)
else if(BSPF_equalsIgnoreCase(c, "pc"))
return &CpuDebug::pc;
else if(strcmp(c, "sp") == 0)
else if(BSPF_equalsIgnoreCase(c, "sp"))
return &CpuDebug::sp;
else if(strcmp(c, "c") == 0)
else if(BSPF_equalsIgnoreCase(c, "c"))
return &CpuDebug::c;
else if(strcmp(c, "z") == 0)
else if(BSPF_equalsIgnoreCase(c, "z"))
return &CpuDebug::z;
else if(strcmp(c, "n") == 0)
else if(BSPF_equalsIgnoreCase(c, "n"))
return &CpuDebug::n;
else if(strcmp(c, "v") == 0)
else if(BSPF_equalsIgnoreCase(c, "v"))
return &CpuDebug::v;
else if(strcmp(c, "d") == 0)
else if(BSPF_equalsIgnoreCase(c, "d"))
return &CpuDebug::d;
else if(strcmp(c, "i") == 0)
else if(BSPF_equalsIgnoreCase(c, "i"))
return &CpuDebug::i;
else if(strcmp(c, "b") == 0)
else if(BSPF_equalsIgnoreCase(c, "b"))
return &CpuDebug::b;
else
return 0;
@ -202,9 +203,9 @@ CPUDEBUG_INT_METHOD getCpuSpecial(char *c)
// special methods that get Cart RAM/ROM internal state
CARTDEBUG_INT_METHOD getCartSpecial(char *c)
{
if(strcmp(c, "_bank") == 0)
if(BSPF_equalsIgnoreCase(c, "_bank"))
return &CartDebug::getBank;
else if(strcmp(c, "_rwport") == 0)
else if(BSPF_equalsIgnoreCase(c, "_rwport"))
return &CartDebug::readFromWritePort;
else
return 0;
@ -213,15 +214,15 @@ CARTDEBUG_INT_METHOD getCartSpecial(char *c)
// special methods that get TIA internal state
TIADEBUG_INT_METHOD getTiaSpecial(char *c)
{
if(strcmp(c, "_scan") == 0)
if(BSPF_equalsIgnoreCase(c, "_scan"))
return &TIADebug::scanlines;
else if(strcmp(c, "_fcount") == 0)
else if(BSPF_equalsIgnoreCase(c, "_fcount"))
return &TIADebug::frameCount;
else if(strcmp(c, "_cclocks") == 0)
else if(BSPF_equalsIgnoreCase(c, "_cclocks"))
return &TIADebug::clocksThisLine;
else if(strcmp(c, "_vsync") == 0)
else if(BSPF_equalsIgnoreCase(c, "_vsync"))
return &TIADebug::vsyncAsInt;
else if(strcmp(c, "_vblank") == 0)
else if(BSPF_equalsIgnoreCase(c, "_vblank"))
return &TIADebug::vblankAsInt;
else
return 0;