def tokenize_non_expanded_string( start_delimiter )
      delimiter_depth = 0
      matched_delimiter = is_matched_delimiter?( start_delimiter )
      end_delimiter = find_matching_delimiter( start_delimiter )

      advance # Pass the opening delimiter

      until((cchar == end_delimiter && delimiter_depth == 0) || @i >= @length)

        if matched_delimiter
          delimiter_depth += 1 if cchar == start_delimiter
          delimiter_depth -= 1 if cchar == end_delimiter
        end

        if cchar == '\\'
          advance(2) # Pass the escaped character
        else
          advance
        end
      end
      advance # Pass the closing quote

      if @state == :regex
        advance if ['i', 'm'].include?( cchar )
      end

      @expr_state = :end
      capture_token( @state )
    end
def tokenize_non_expanded_string( start_delimiter )
      delimiter_depth = 0
      matched_delimiter = is_matched_delimiter?( start_delimiter )
      end_delimiter = find_matching_delimiter( start_delimiter )

      advance # Pass the opening delimiter

      until((cchar == end_delimiter && delimiter_depth == 0) || @i >= @length)

        if matched_delimiter
          delimiter_depth += 1 if cchar == start_delimiter
          delimiter_depth -= 1 if cchar == end_delimiter
        end

        if cchar == '\\'
          advance(2) # Pass the escaped character
        else
          advance
        end
      end
      advance # Pass the closing quote

      if @state == :regex
        advance if ['i', 'm'].include?( cchar )
      end

      @expr_state = :end
      capture_token( @state )
    end
If a block is given, it gets run after the final delimiter is detected. The
 primary purpose for this is to allow the capture of regex modifiers