/**
  * Gets the next token from a tokenizer and converts it to a string.
  *
  * @return The next token in the stream, as a string.
  * @throws TextParseException The input was invalid or not a string.
  * @throws IOException An I/O error occurred.
  */
 public String getString() throws IOException {
   Token next = get();
   if (!next.isString()) {
     throw exception("expected a string");
   }
   return next.value;
 }
  /**
   * Gets the next token from a tokenizer.
   *
   * @param wantWhitespace If true, leading whitespace will be returned as a token.
   * @param wantComment If true, comments are returned as tokens.
   * @return The next token in the stream.
   * @throws TextParseException The input was invalid.
   * @throws IOException An I/O error occurred.
   */
  public Token get(boolean wantWhitespace, boolean wantComment) throws IOException {
    int type;
    int c;

    if (ungottenToken) {
      ungottenToken = false;
      if (current.type == WHITESPACE) {
        if (wantWhitespace) return current;
      } else if (current.type == COMMENT) {
        if (wantComment) return current;
      } else {
        if (current.type == EOL) line++;
        return current;
      }
    }
    int skipped = skipWhitespace();
    if (skipped > 0 && wantWhitespace) return current.set(WHITESPACE, null);
    type = IDENTIFIER;
    sb.setLength(0);
    while (true) {
      c = getChar();
      if (c == -1 || delimiters.indexOf(c) != -1) {
        if (c == -1) {
          if (quoting) throw exception("EOF in " + "quoted string");
          else if (sb.length() == 0) return current.set(EOF, null);
          else return current.set(type, sb);
        }
        if (sb.length() == 0 && type != QUOTED_STRING) {
          if (c == '(') {
            multiline++;
            skipWhitespace();
            continue;
          } else if (c == ')') {
            if (multiline <= 0) throw exception("invalid " + "close " + "parenthesis");
            multiline--;
            skipWhitespace();
            continue;
          } else if (c == '"') {
            if (!quoting) {
              quoting = true;
              delimiters = quotes;
              type = QUOTED_STRING;
            } else {
              quoting = false;
              delimiters = delim;
              skipWhitespace();
            }
            continue;
          } else if (c == '\n') {
            return current.set(EOL, null);
          } else if (c == ';') {
            while (true) {
              c = getChar();
              if (c == '\n' || c == -1) break;
              sb.append((char) c);
            }
            if (wantComment) {
              ungetChar(c);
              return current.set(COMMENT, sb);
            } else if (c == -1 && type != QUOTED_STRING) {
              checkUnbalancedParens();
              return current.set(EOF, null);
            } else if (multiline > 0) {
              skipWhitespace();
              sb.setLength(0);
              continue;
            } else return current.set(EOL, null);
          } else throw new IllegalStateException();
        } else ungetChar(c);
        break;
      } else if (c == '\\') {
        c = getChar();
        if (c == -1) throw exception("unterminated escape sequence");
        sb.append('\\');
      } else if (quoting && c == '\n') {
        throw exception("newline in quoted string");
      }
      sb.append((char) c);
    }
    if (sb.length() == 0 && type != QUOTED_STRING) {
      checkUnbalancedParens();
      return current.set(EOF, null);
    }
    return current.set(type, sb);
  }