2012-02-08 75 views
2

我正在将源文件拆分为令牌,特别是扫描标识符。但是,要求标识符长达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 
+1

例外应仅用于“例外”情况。不要试图用它们创建程序流。只需从您的方法中返回令牌。 – 2012-02-08 05:10:03

+0

这不是一个程序流程问题。我需要向正在使用该程序的人发出警告,说明他们的标识符太长,并且正在被截断。我认为一个例外将是这样做的合理方法。什么会是一个很好的选择? – 2012-02-08 05:11:59

+0

让我把它变成一个答案。 – 2012-02-08 05:28:02

回答

3

这是滥用例外情况的IMO,因为这不是特例。相反,考虑简单地记录了一句:

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

如果必须使用除外出于某种原因,那么最简单的方法就是把this_id在一个实例变量来代替:

@this_identifier = id 
# ... 

然后,当你打破了救援,只是最后一个表达式是@this_identifier返回该值(yuck)。


奖金评论:这是解析源文件真正的猥琐方式。如果你在解析Ruby,你应该使用类似RubyParserTreetop如果你解析别的东西。

+0

不幸的是,这是一个项目,我从头开始编译编译器。如果我有选择,我会使用lex和yacc来避免这部分编译。另外,这种方法有什么不好? (除了滥用异常) – 2012-02-08 05:19:49

+0

对于初学者来说,你的标记器可以短得多,因为它的唯一作用是解析出标识符并忽略其他所有内容。只是分词,并对每个超过30个字符的人发出警告:'好,坏= @ infile.read.split.partition {| word | word.length <30}'。 – 2012-02-08 05:21:58

+0

我抽象了其余的标记器,它实际上标记了完整的输入语言正确。除了我发布的案例外。我解析的源文件可以包含任何可能在PL/0程序中的内容。 – 2012-02-08 05:24:26

1

例外应仅用于“例外”情况。不要试图用它们创建程序流。只需从您的方法中返回令牌。

类似的规定:

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 

当你需要提醒你的东西,他们正在做的用户在正常使用情况下,一般预料,只是输出字符串到标准输出或/和标准错误的情况下控制台应用程序。