docs: private String readString() throws IOException {
          StringBuffer sb    = new StringBuffer();
          int          delim = lastChar;
          int          l = lineNo;
          int          c = colNo;
  
          readChar();
          while ((-1 != lastChar) && (delim != lastChar))
          {
              StringBuffer digitBuffer;
  
              if (lastChar != '\\')
              {
                  sb.append((char)lastChar);
                  readChar();
                  continue;
              }
  
              readChar();
  
              switch (lastChar)
              {
                  case 'b':  readChar(); sb.append('\b'); continue; 
                  case 'f':  readChar(); sb.append('\f'); continue; 
                  case 'n':  readChar(); sb.append('\n'); continue; 
                  case 'r':  readChar(); sb.append('\r'); continue; 
                  case 't':  readChar(); sb.append('\t'); continue; 
                  case '\'': readChar(); sb.append('\''); continue; 
                  case '"':  readChar(); sb.append('"');  continue; 
                  case '\\': readChar(); sb.append('\\'); continue;
                  case '/': readChar();  sb.append('/'); continue;
  
                      // hex constant
                      // unicode constant
                  case 'x':
                  case 'u':
                      digitBuffer = new StringBuffer();
  
                      int toRead = 2;
                      if (lastChar == 'u') toRead = 4;
  
                      for (int i=0; i<toRead; i++)
                      {
                          readChar();
                          if (!isHexDigit(lastChar)) throw new IOException("non-hex digit " + onLineCol());
                          digitBuffer.append((char) lastChar);
                      }
                      readChar();
  
                      try
                      {
                          int digitValue = Integer.parseInt(digitBuffer.toString(), 16);
                          sb.append((char) digitValue);
                      }
                      catch (NumberFormatException e)
                      {
                          throw new IOException("non-hex digit " + onLineCol());
                      }
  
                      break;
  
                      // octal constant
                  default:
                      if (!isOctalDigit(lastChar)) throw new IOException("non-hex digit " + onLineCol());
  
                      digitBuffer = new StringBuffer();
                      digitBuffer.append((char) lastChar);
  
                      for (int i=0; i<2; i++)
                      {
                          readChar();
                          if (!isOctalDigit(lastChar)) break;
  
                          digitBuffer.append((char) lastChar);
                      }
  
                      try
                      {
                          int digitValue = Integer.parseInt(digitBuffer.toString(), 8);
                          sb.append((char) digitValue);
                      }
                      catch (NumberFormatException e)
                      {
                          throw new IOException("non-hex digit " + onLineCol());
                      }
              }
          }
  
          if (-1 == lastChar)
          {
              throw new IOException("String not terminated " + onLineCol(l,c));
          }
  
          readChar();
  
          return sb.toString();
      }