Сохранить переменную после возникновения исключения - PullRequest
2 голосов
/ 08 февраля 2012

Я работаю над разбиением исходного файла на токены, в частности, проверкой идентификаторов.Однако существует требование, чтобы идентификаторы были длиной не более 30 символов.Когда идентификатор достигает этой длины, я выдаю исключение с сообщением: 'Identifiers can only be 30 characters long, truncating..'.

Так и должно быть, но, когда я поднимаю это исключение, я выскакиваю из своего метода, который сканирует идентификаторы, прежде чем я смог сохранить его.Мне нужно как-то вызвать исключение И сохранить идентификатор, который я собрал до сих пор.Есть идеи, как это можно сделать?

# classify each character, and call approriate scan methods
def tokenize()
  @infile.each_char do |c|
    begin
      case c
      when /[a-zA-Z\$]/
        scan_identifier(c)
      when /\s/ 
        #ignore spaces
      else
        #do nothing
      end
    rescue TokenizerError => te
      puts "#{te.class}: #{te.message}"
    end
  end
end

# Reads an identifier from the source program
def scan_identifier(id)
  this_id = id #initialize this identifier with the character read above

  @infile.each_char do |c|
    if c =~ /[a-zA-Z0-9_]/
      this_id += c 
      # raising this exception leaves this function before collecting the 
      # truncated identifier
      raise TokenizerError, 'Identifiers can only be 30 characters long, truncating..' if this_id.length == 30
    else 
      puts "#{this_id}"
      break # not part of the identifier, or an error
    end
  end
end

Ответы [ 2 ]

3 голосов
/ 08 февраля 2012

Это злоупотребление исключениями, ИМО, потому что это не исключительный случай. Вместо этого рассмотрите возможность регистрации чего-либо:

    if c =~ /[a-zA-Z0-9_]/
      warn "Identifer was too long and was truncated"
      this_id += c 

Если вы по какой-то причине должны использовать исключение, то самый простой способ - просто поместить this_id в переменную экземпляра:

@this_identifier = id
# ...

Затем, когда вы прервете спасение, просто возьмите последнее выражение @this_identifier, чтобы вернуть это значение (гадость).

<Ч />

Бонусный комментарий: это действительно ужасный способ разбора исходных файлов. Вы должны использовать что-то вроде RubyParser , если вы анализируете Ruby, или Treetop , если вы анализируете что-то еще.

1 голос
/ 08 февраля 2012

Исключения следует использовать только в «исключительных» случаях. Не пытайтесь создать поток программ с ними. Просто верните токен из вашего метода.

Что-то в этом роде:

 def tokenize()
    @infile.each_char do |c|
      begin
        case c
        when /[a-zA-Z\$]/
          scan_identifier(c)
        when /\s/ 
          #ignore spaces
        else
          #do nothing
        end
      end
    end
  end

  #Reads an identifier from the source program
  def scan_identifier(id)
    this_id = id #initialize this identifier with the character read above

    @infile.each_char do |c|
        if c =~ /[a-zA-Z0-9_]/
          this_id += c 
          if this_id.length == 30
            puts 'Identifiers can only be 30 characters long, truncating..'
            break
          end
        else 
          break #not part of the identifier, or an error
        end
    end
    puts "#{this_id}"
  end

Если вам нужно предупредить пользователей о том, что они делают, это в обычном случае и обычно ожидаемо, просто выведите строку в stdout или / и stderr в случае консольного приложения.

...