public function parseOne(string $input, int $pos, array $preferredTokens = []): ?Match
    {
        $length = strlen($input);
        if ($pos >= $length) {
            return null;
        }

        $this->compile();

        $whitespace_length = $this->getWhitespaceLength($input, $pos);
        if ($whitespace_length) {
            $pos += $whitespace_length;
            if ($pos >= $length) {
                return null;
            }
        }

        $match = $this->match($input, $pos, $preferredTokens);
        if (!$match) {
            $near = substr($input, $pos, self::DUMP_NEAR_LENGTH);
            if ("" === $near || false === $near) {
                $near = '<EOF>';
            } else {
                $near = '"' . $near . '"';
            }
            throw new UnknownCharacterException(
                "Cannot parse none of expected tokens near $near",
                $pos
            );
        }

        return $match;
    }