Index: /trunk/src/VBox/Debugger/DBGCCmdHlp.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGCCmdHlp.cpp	(revision 41570)
+++ /trunk/src/VBox/Debugger/DBGCCmdHlp.cpp	(revision 41571)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -1198,12 +1198,5 @@
                         rc = dbgcSymbolGet(pDbgc, InVar.u.pszString, enmToType, pResult);
                         if (RT_SUCCESS(rc))
-                        {
-                            if (InVar.enmRangeType != DBGCVAR_RANGE_NONE)
-                            {
-                                pResult->enmRangeType = InVar.enmRangeType;
-                                pResult->u64Range     = InVar.u64Range;
-                            }
                             return VINF_SUCCESS;
-                        }
                     }
                     return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
Index: /trunk/src/VBox/Debugger/DBGCCommands.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGCCommands.cpp	(revision 41570)
+++ /trunk/src/VBox/Debugger/DBGCCommands.cpp	(revision 41571)
@@ -1064,4 +1064,11 @@
                 break;
 
+            case DBGCVAR_TYPE_SYMBOL:
+                rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
+                    "Symbol, %lld bytes long: %s\n",
+                    paArgs[iArg].u64Range,
+                    paArgs[iArg].u.pszString);
+                break;
+
             case DBGCVAR_TYPE_NUMBER:
                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
Index: /trunk/src/VBox/Debugger/DBGCEval.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGCEval.cpp	(revision 41570)
+++ /trunk/src/VBox/Debugger/DBGCEval.cpp	(revision 41571)
@@ -76,23 +76,88 @@
 
 
-
-static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
+/**
+ * Returns the amount of free scratch space.
+ *
+ * @returns Number of unallocated bytes.
+ * @param   pDbgc               The DBGC instance.
+ */
+size_t dbgcGetFreeScratchSpace(PDBGC pDbgc)
 {
-    Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
+    return sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
+}
+
+
+/**
+ * Allocates a string from the scratch space.
+ *
+ * @returns Pointer to the allocated string buffer, NULL if out of space.
+ * @param   pDbgc               The DBGC instance.
+ * @param   cbRequested         The number of bytes to allocate.
+ */
+char *dbgcAllocStringScatch(PDBGC pDbgc, size_t cbRequested)
+{
+    if (cbRequested > dbgcGetFreeScratchSpace(pDbgc))
+        return NULL;
+    char *psz = pDbgc->pszScratch;
+    pDbgc->pszScratch += cbRequested;
+    return psz;
+}
+
+
+/**
+ * Evals an expression into a string or symbol (single quotes).
+ *
+ * The string memory is allocated from the scratch buffer.
+ *
+ * @returns VBox status code.
+ * @param   pDbgc               The DBGC instance.
+ * @param   pachExpr            The string/symbol expression.
+ * @param   cchExpr             The length of the expression.
+ * @param   pArg                Where to return the string.
+ */
+static int dbgcEvalSubString(PDBGC pDbgc, const char *pachExpr, size_t cchExpr, PDBGCVAR pArg)
+{
+    Log2(("dbgcEvalSubString: cchExpr=%d pachExpr=%.*s\n", cchExpr, cchExpr, pachExpr));
+
+    /*
+     * Allocate scratch space for the string.
+     */
+    char *pszCopy = dbgcAllocStringScatch(pDbgc, cchExpr + 1);
+    if (!pszCopy)
+        return VERR_DBGC_PARSE_NO_SCRATCH;
 
     /*
      * Removing any quoting and escapings.
      */
-    char ch = *pszExpr;
-    if (ch == '"' || ch == '\'')
-    {
-        if (pszExpr[--cchExpr] != ch)
+    char const chQuote = *pachExpr;
+    if (chQuote == '"' || chQuote == '\'')
+    {
+        if (pachExpr[--cchExpr] != chQuote)
             return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
+
         cchExpr--;
-        pszExpr++;
-
-        /** @todo string unescaping. */
-    }
-    pszExpr[cchExpr] = '\0';
+        pachExpr++;
+        if (!memchr(pachExpr, chQuote, cchExpr))
+            memcpy(pszCopy, pachExpr, cchExpr);
+        else
+        {
+            size_t offSrc = 0;
+            size_t offDst = 0;
+            while (offSrc < cchExpr)
+            {
+                char const ch = pachExpr[offSrc++];
+                if (ch == chQuote)
+                {
+                    if (pachExpr[offSrc] != ch)
+                        return VERR_DBGC_PARSE_EXPECTED_BINARY_OP;
+                    offSrc++;
+                }
+                pszCopy[offDst++] = ch;
+            }
+        }
+    }
+    else
+        memcpy(pszCopy, pachExpr, cchExpr);
+    pszCopy[cchExpr] = '\0';
 
     /*
@@ -101,6 +166,6 @@
     pArg->pDesc         = NULL;
     pArg->pNext         = NULL;
-    pArg->enmType       = DBGCVAR_TYPE_STRING;
-    pArg->u.pszString   = pszExpr;
+    pArg->enmType       = chQuote == '\'' ? DBGCVAR_TYPE_SYMBOL : DBGCVAR_TYPE_STRING;
+    pArg->u.pszString   = pszCopy;
     pArg->enmRangeType  = DBGCVAR_RANGE_BYTES;
     pArg->u64Range      = cchExpr;
@@ -111,14 +176,21 @@
 
 
-static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
+static int dbgcEvalSubNum(const char *pachExpr, size_t cchExpr, unsigned uBase, PDBGCVAR pArg)
 {
-    Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
+    Log2(("dbgcEvalSubNum: uBase=%d pachExpr=%.*s\n", uBase, cchExpr, pachExpr));
+
+    /*
+     * Empty expressions cannot be valid numbers.
+     */
+    if (!cchExpr)
+        return VERR_DBGC_PARSE_INVALID_NUMBER;
+
     /*
      * Convert to number.
      */
     uint64_t    u64 = 0;
-    char        ch;
-    while ((ch = *pszExpr) != '\0')
-    {
+    while (cchExpr-- > 0)
+    {
+        char const ch = *pachExpr;
         uint64_t    u64Prev = u64;
         unsigned    u = ch - '0';
@@ -137,5 +209,5 @@
 
         /* next */
-        pszExpr++;
+        pachExpr++;
     }
 
@@ -172,5 +244,5 @@
     /* 0x<hex digits> */
     if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
-        return dbgcEvalSubNum(pszExpr + 2, 16, pResult);
+        return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 16, pResult);
 
     /* <hex digits>h */
@@ -178,28 +250,29 @@
     {
         pszExpr[cchExpr] = '\0';
-        return dbgcEvalSubNum(pszExpr, 16, pResult);
+        return dbgcEvalSubNum(pszExpr, cchExpr - 1, 16, pResult);
     }
 
     /* 0i<decimal digits> */
     if (ch == '0' && ch2 == 'i')
-        return dbgcEvalSubNum(pszExpr + 2, 10, pResult);
+        return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 10, pResult);
 
     /* 0t<octal digits> */
     if (ch == '0' && ch2 == 't')
-        return dbgcEvalSubNum(pszExpr + 2, 8, pResult);
+        return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 8, pResult);
 
     /* 0y<binary digits> */
     if (ch == '0' && ch2 == 'y')
-        return dbgcEvalSubNum(pszExpr + 2, 10, pResult);
+        return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 10, pResult);
 
     /* Hex number? */
     unsigned off = 0;
-    while (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`')
+    while (off < cchExpr && (RT_C_IS_XDIGIT(pszExpr[off]) || pszExpr[off] == '`'))
         off++;
     if (off == cchExpr)
-        return dbgcEvalSubNum(pszExpr, 16, pResult);
-
-    /*
-     * Some kind of symbol?
+        return dbgcEvalSubNum(pszExpr, cchExpr, 16, pResult);
+
+    /*
+     * Some kind of symbol?  Rejected double quoted strings, only unquoted
+     * and single quoted strings will be considered as symbols.
      */
     DBGCVARTYPE enmType;
@@ -219,7 +292,12 @@
     }
 
-    if (   (*pszExpr == '"' || *pszExpr == '\'')
-        && pszExpr[cchExpr - 1] == *pszExpr)
-    {
+    char const chQuote = *pszExpr;
+    if (chQuote == '"')
+        return VERR_DBGC_PARSE_INVALID_NUMBER;
+
+    if (chQuote == '\'')
+    {
+        if (pszExpr[cchExpr - 1] != chQuote)
+            return VERR_DBGC_PARSE_UNBALANCED_QUOTE;
         pszExpr[cchExpr - 1] = '\0';
         pszExpr++;
@@ -262,5 +340,5 @@
             off++;
         if (off == cchExpr)
-            return dbgcEvalSubNum(pszExpr + 2, 16, pResult);
+            return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 16, pResult);
         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
     }
@@ -275,16 +353,16 @@
         {
             pszExpr[cchExpr] = '\0';
-            return dbgcEvalSubNum(pszExpr, 16, pResult);
+            return dbgcEvalSubNum(pszExpr, cchExpr, 16, pResult);
         }
         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr + 1, pResult);
     }
 
-    /* 0i<decimal digits> */
-    if (ch == '0' && ch2 == 'i')
+    /* 0n<decimal digits> or 0i<decimal digits> */
+    if (ch == '0' && (ch2 == 'n' || ch2 == 'i'))
     {
         while (RT_C_IS_DIGIT(pszExpr[off]) || pszExpr[off] == '`')
             off++;
         if (off == cchExpr)
-            return dbgcEvalSubNum(pszExpr + 2, 10, pResult);
+            return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 10, pResult);
         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
     }
@@ -296,5 +374,5 @@
             off++;
         if (off == cchExpr)
-            return dbgcEvalSubNum(pszExpr + 2, 8, pResult);
+            return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 8, pResult);
         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
     }
@@ -306,5 +384,5 @@
             off++;
         if (off == cchExpr)
-            return dbgcEvalSubNum(pszExpr + 2, 10, pResult);
+            return dbgcEvalSubNum(pszExpr + 2, cchExpr - 2, 10, pResult);
         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
     }
@@ -316,5 +394,5 @@
         off++;
     if (off == cchExpr)
-        return dbgcEvalSubNum(pszExpr, 16, pResult);
+        return dbgcEvalSubNum(pszExpr, cchExpr, 16, pResult);
     return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
 }
@@ -537,11 +615,4 @@
         } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
     }
-
-#if 0  /* why was this needed? It'll screw up strings. */
-    /* tabs to spaces */
-    char *psz = pszExpr;
-    while ((psz = strchr(psz, '\t')) != NULL)
-        *psz = ' ';
-#endif
 
     /*
Index: /trunk/src/VBox/Debugger/DBGConsole.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGConsole.cpp	(revision 41570)
+++ /trunk/src/VBox/Debugger/DBGConsole.cpp	(revision 41571)
@@ -20,19 +20,27 @@
  *
  * The debugger console is an early attempt to make some interactive
- * debugging facilities for the VirtualBox VMM. It was initially only
- * accessible thru a telnet session on debug builds. Later it was hastily
- * built into the VBoxDbg module with a very simple Qt wrapper around it.
- *
- * The debugger is optional and presently not built into release builds
- * of VirtualBox. It is therefore necessary to enclose code related to it
- * in \#ifdef VBOX_WITH_DEBUGGER blocks. This is mandatory for components
- * that register extenral commands.
- *
- *
- * @section sec_dbgc_op                 Operation (intentions)
- *
- * The console will process commands in a manner similar to the OS/2 and
- * windows kernel debuggers. This means ';' is a command separator and
- * that when possible we'll use the same command names as these two uses.
+ * debugging facilities for the VirtualBox VMM.  It was initially only
+ * accessible thru a telnet session in debug builds.  Later it was hastily built
+ * into the VBoxDbg module with a very simple Qt wrapper around it.
+ *
+ * The current state is that it's by default shipped with all standard
+ * VirtualBox builds.  The GUI component is by default accessible in all
+ * non-release builds, while release builds require extra data, environment or
+ * command line options to make it visible.
+ *
+ * Now, even if we ship it with all standard builds we would like it to remain
+ * an optional feature that can be omitted when building VirtualBox.  Therefore,
+ * all external code interfacing DBGC need to be enclosed in
+ * \#ifdef VBOX_WITH_DEBUGGER blocks. This is mandatory for components that
+ * register external commands.
+ *
+ *
+ * @section sec_dbgc_op                 Operation
+ *
+ * The console will process commands in a manner similar to the OS/2 and Windows
+ * kernel debuggers.  This means ';' is a command separator and that when
+ * possible we'll use the same command names as these two uses.  As an
+ * alternative we intent to provide a set of gdb-like commands as well and let
+ * the user decide which should take precedence.
  *
  *
@@ -42,12 +50,34 @@
  * elsewise. Prefixes:
  *      - '0x' - hexadecimal.
- *      - '0i' - decimal
+ *      - '0n' - decimal
  *      - '0t' - octal.
  *      - '0y' - binary.
  *
- * Some of the prefixes are a bit uncommon, the reason for this that
- * the typical binary prefix '0b' can also be a hexadecimal value since
- * no prefix or suffix is required for such values. Ditto for '0d' and
- * '0' for decimal and octal.
+ * Some of the  prefixes are a bit uncommon, the reason for this that the
+ * typical binary prefix '0b' can also be a hexadecimal value since no prefix or
+ * suffix is required for such values. Ditto for '0n' and '0' for decimal and
+ * octal.
+ *
+ * The '`' can be used in the numeric value to separate parts as the user
+ * wishes.  Generally, though the debugger may use it in output as thousand
+ * separator in decimal numbers and 32-bit separator in hex numbers.
+ *
+ * For historical reasons, a 'h' suffix is suffered on hex numbers.  Unlike most
+ * assemblers, a leading 0 before a-f is not required with the 'h' suffix.
+ *
+ * The prefix '0i' can be used instead of '0n', as it was the early decimal
+ * prefix employed by DBGC.  It's being deprecated and may be removed later.
+ *
+ *
+ * @subsection sec_dbg_op_strings       Strings and Symbols
+ *
+ * The debugger will try to guess, convert or promote what the type of an
+ * argument to a command, function or operator based on the input description of
+ * the receiver.  If the user wants to make it clear to the debugger that
+ * something is a string, put it inside double quotes.  Symbols should use
+ * single quotes, though we're current still a bit flexible on this point.
+ *
+ * If you need to put a quote character inside the quoted text, you escape it by
+ * repating it once: echo "printf(""hello world"");"
  *
  *
@@ -62,47 +92,45 @@
  *
  * The '%', '%%' and '#' prefixes is implemented as unary operators, while ':'
- * is a binary operator. Operator precedence takes care of evaluation order.
- *
- *
- * @subsection sec_dbg_op_evalution     Evaluation
- *
- * Most unary and binary C operators are supported, check the help text for
- * details. However, some of these are not yet implemented because this is
- * tiresome and annoying work. So, if something is missing and you need it
- * you implement it or complain to bird. (Ditto for missing functions.)
- *
- * Simple variable support is provided thru the 'set' and 'unset' commands and
- * the unary '$' operator.
- *
- * The unary '@' operator will indicate function calls. Commands and functions
- * are the same thing, except that functions has a return type.
+ * is a binary operator.  Operator precedence takes care of evaluation order.
+ *
+ *
+ * @subsection sec_dbg_op_c_operators   C/C++ Operators
+ *
+ * Most unary and binary arithmetic, comparison, logical and bitwise C/C++
+ * operators are supported by the debugger, with the same precedence rules of
+ * course.  There is one notable change made due to the unary '%' and '%%'
+ * operators, and that is that the modulo (remainder) operator is called 'mod'
+ * instead of '%'.  This saves a lot of trouble separating argument.
+ *
+ * There are no assignment operators.  Instead some simple global variable space
+ * is provided thru the 'set' and 'unset' commands and the unary '$' operator.
  *
  *
  * @subsection sec_dbg_op_registers     Registers
  *
- * Registers are addressed using their name. Some registers which have several fields
- * (like gdtr) will have separate names indicating the different fields. The default
- * register set is the guest one. To access the hypervisor register one have to
- * prefix the register names with '.'.
- *
- * The registers are implemented as built-in symbols. For making gdb guys more at
- * home it is possible to access them with the '$' operator, i.e. as a variable.
- *
- *
- * @subsection sec_dbg_op_commands      Commands and Functions
- *
- * Commands and functions are the same thing, except that functions may return a
- * value. So, functions may be used as commands. The command/function handlers
- * can detect whether they are invoked as a command or function by checking whether
- * there is a return variable or not.
- *
- * The command/function names are all lowercase, case sensitive, and starting
- * with a letter. Operator characters are not permitted in the names of course.
- * Space is allowed, but must be flagged so the parser can check for multiple
- * spaces and tabs. (This feature is for 'dump xyz' and for emulating the
- * gdb 'info abc'.)
+ * All registers and their sub-fields exposed by the DBGF API are accessible via
+ * the '\@' operator.  A few CPU register are accessible directly (as symbols)
+ * without using the '\@' operator.  Hypervisor registers are accessible by
+ * prefixing the register name with a dot ('.').
+ *
+ *
+ * @subsection sec_dbg_op_commands      Commands
+ *
+ * Commands names are case sensitive. By convention they are lower cased, starts
+ * with a letter but may contain digits and underscores afterwards.  Operators
+ * are not allowed in the name (not even part of it), as we would risk
+ * misunderstanding it otherwise.
+ *
+ * Commands returns a status code.
  *
  * The '.' prefix indicates the set of external commands. External commands are
  * command registered by VMM components.
+ *
+ *
+ * @subsection sec_dbg_op_functions     Functions
+ *
+ * Functions are similar to commands, but return a variable and can only be used
+ * as part of an expression making up the argument of a command, function,
+ * operator or language statement (if we get around to implement that).
  *
  *
@@ -114,15 +142,15 @@
  * (dbgcProcessLog and DBGC::fLog).
  *
+ * This feature has not materialized and probably never will.
  *
  *
  * @section sec_dbgc_linking            Linking and API
  *
- * The DBGC code is linked into the VBoxVMM module. (At present it is also
- * linked into VBoxDbg, but this is obviously very wrong.)
- *
- * A COM object will be created for the DBGC so it can be operated remotely
- * without using TCP. VBoxDbg is the intended audience for this usage. Some
- * questions about callbacks (for output) and security (you may wish to
- * restrict users from debugging a VM) needs to be answered first though.
+ * The DBGC code is linked into the VBoxVMM module.
+ *
+ * IMachineDebugger may one day be extended with a DBGC interface so we can work
+ * with DBGC remotely without requiring TCP.  Some questions about callbacks
+ * (for output) and security (you may wish to restrict users from debugging a
+ * VM) needs to be answered first though.
  */
 
@@ -218,5 +246,5 @@
             rc = dbgcOpRegister(pDbgc, &Var, DBGCVAR_CAT_ANY, pResult);
             if (RT_SUCCESS(rc))
-                return DBGCCmdHlpConvert(&pDbgc->CmdHlp, &Var, enmType, false /*fConvSyms*/, pResult);
+                return DBGCCmdHlpConvert(&pDbgc->CmdHlp, pResult, enmType, false /*fConvSyms*/, pResult);
         }
     }
Index: /trunk/src/VBox/Debugger/testcase/tstDBGCParser.cpp
===================================================================
--- /trunk/src/VBox/Debugger/testcase/tstDBGCParser.cpp	(revision 41570)
+++ /trunk/src/VBox/Debugger/testcase/tstDBGCParser.cpp	(revision 41571)
@@ -1140,4 +1140,6 @@
     tstTry(pDbgc, "format nosuchfunction()\n", VERR_DBGC_PARSE_FUNCTION_NOT_FOUND);
     tstTry(pDbgc, "format randu32()\n", VINF_SUCCESS);
+    tstTryEx(pDbgc, "format %0\n", VINF_SUCCESS, false, "Guest flat address: %00000000", -1);
+    tstTryEx(pDbgc, "format %eax\n", VINF_SUCCESS, false, "Guest flat address: %cafebabe", -1);
     tstTry(pDbgc, "sa 3 23 4 'q' \"21123123\" 'b' \n", VINF_SUCCESS);
     tstTry(pDbgc, "sa 3,23, 4,'q' ,\"21123123\" , 'b' \n", VINF_SUCCESS);
