2012-02-08 14 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

例外は「例外的」な場合にのみ使用してください。プログラムフローを作成しようとしないでください。メソッドからトークンを返すだけです。 –

+0

プログラムフローの問題ではありませんでした。私は、識別子が長すぎて切り捨てられているプログラムを使用している人には警告を発する必要があります。私は例外がそれを行うための論理的方法であると考えました。良い選択肢は何でしょうか? –

+0

これを答えにしてみましょう。 –

答えて

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を解析する場合はRubyParser、その他の場合はTreetopのようなものを使用する必要があります。

+0

残念ながら、これは私が最初からコンパイラをビルドしているプロジェクトです。選択肢があれば、lexとyaccを使ってコンパイルのこの部分を避けます。また、このアプローチについては何が悪いですか? (例外的な濫用の他に) –

+0

初心者のために、あなたのトークナイザは、識別子を解析して他のすべてを無視するという唯一の効果があるので、はるかに短くすることができます。単語を分割して、30文字を超えるそれぞれについて警告してください: 'good、bad = @ infile.read.split.partition {| word | word.length <30} 'となります。 –

+0

トークナイザの残りの部分を抽象化しました。実際には完全に入力言語を正しくトークン化しています。ケースを除いて、私は約投稿しました。私が解析するソースファイルには、PL/0プログラムに含まれるものを含めることができます。 –

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 

は、通常の使用ケースとした場合の標準出力または/およびstderrに一般的に期待される、単純に出力文字列です。コンソールアプリケーション。

関連する問題