Ruby 在引发异常后保留变量

Ruby 在引发异常后保留变量,ruby,lexical-analysis,Ruby,Lexical Analysis,我正在将源文件拆分为令牌,特别是扫描标识符。但是,有一项要求是标识符的长度不得超过30个字符。当标识符达到此长度时,我会发出一条异常消息:“标识符长度只能为30个字符,正在截断…” 应该是这样的,但是当我提出这个异常时,我跳出了我的方法,在我能够存储它之前扫描标识符。我需要以某种方式引发异常并保留到目前为止收集的标识符。关于如何做到这一点,有什么想法吗 # classify each character, and call approriate scan methods def tokenize

我正在将源文件拆分为令牌,特别是扫描标识符。但是,有一项要求是标识符的长度不得超过30个字符。当标识符达到此长度时,我会发出一条异常消息:
“标识符长度只能为30个字符,正在截断…”

应该是这样的,但是当我提出这个异常时,我跳出了我的方法,在我能够存储它之前扫描标识符。我需要以某种方式引发异常并保留到目前为止收集的标识符。关于如何做到这一点,有什么想法吗

# 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

海事组织,这是滥用例外,因为这不是例外情况。相反,考虑简单地记录一些东西:

    if c =~ /[a-zA-Z0-9_]/
      warn "Identifer was too long and was truncated"
      this_id += c 
如果出于某种原因必须使用异常,那么最简单的方法就是将
此\u id
放在实例变量中:

@this_identifier = id
# ...
然后,当您中断救援时,只需将最后一个表达式设为
@this\u identifier
即可返回该值(糟糕)



额外评论:这是一种解析源文件的非常糟糕的方法。如果你在解析Ruby,你应该使用类似于的东西,或者如果你在解析其他东西,你应该使用类似于的东西。

我认为这是对异常的滥用,因为这不是一个例外情况。相反,考虑简单地记录一些东西:

    if c =~ /[a-zA-Z0-9_]/
      warn "Identifer was too long and was truncated"
      this_id += c 
如果出于某种原因必须使用异常,那么最简单的方法就是将
此\u id
放在实例变量中:

@this_identifier = id
# ...
然后,当您中断救援时,只需将最后一个表达式设为
@this\u identifier
即可返回该值(糟糕)



额外评论:这是一种解析源文件的非常糟糕的方法。如果您正在解析Ruby,则应该使用类似于的内容,如果您正在解析其他内容,则应该使用类似于的内容。

异常只应在“异常”情况下使用。不要试图用它们创建程序流。只需从方法返回令牌

大致如下:

 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输出一个字符串。

只有在“异常”情况下才应使用异常。不要试图用它们创建程序流。只需从方法返回令牌

大致如下:

 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输出一个字符串。

异常只应在“异常”情况下使用。不要试图用它们创建程序流。只需从您的方法返回令牌。这不是程序流问题。我需要向使用该程序的人发出警告,警告他们的标识符太长,并且正在被截断。我认为一个例外是这样做的合乎逻辑的方式。什么是一个好的选择?让我把这变成一个答案。例外应该只在“例外”情况下使用。不要试图用它们创建程序流。只需从您的方法返回令牌。这不是程序流问题。我需要向使用该程序的人发出警告,警告他们的标识符太长,并且正在被截断。我认为一个例外是这样做的合乎逻辑的方式。什么是一个好的选择?让我把它变成一个答案。不幸的是,这是一个项目,我正在从头开始构建一个编译器。如果我有选择的话,我会使用lex和yacc来避免编译的这一部分。此外,这种方法有什么不好的地方?(除了异常滥用之外)对于初学者来说,您的标记器可以短得多,因为它唯一的作用是解析出标识符并忽略其他所有内容。只需对超过30个字符的单词进行拆分并发出警告:
good,bad=@infie.read.split.partition{| word | word.length<30}
。我提取了标记器的其余部分,它实际上正确地标记了完整的输入语言。除了我贴出的那个案子。我分析的源文件可以包含PL/0程序中的任何内容。@HunterMcMillen:Alrighty。我仍然认为Treetop更好,因为它是一种更好、更高级的词法分析方法。我同意Treetop更好,但作业要求我从头开始创建它。不幸的是,这是一个我正在从头开始构建编译器的项目。如果我有选择的话,我会使用lex和yacc来避免编译的这一部分。此外,这种方法有什么不好的地方?(除了异常滥用之外)对于初学者来说,您的标记器可以短得多,因为它唯一的作用是解析出标识符并忽略其他所有内容。只需对超过30个字符的单词进行拆分并发出警告:
good,bad=@infie.read.split.partition{| word | word.length<30}
。我提取了标记器的其余部分,它实际上正确地标记了完整的输入语言。除了我贴出的那个案子。我分析的源文件可以包含PL/0程序中的任何内容。@HunterMcMillen:Alrighty。我仍然认为Treetop更好,因为它是一种更好、更高级的词法分析方法。我同意Treetop更好,但作业要求我从头开始创建它。