mcommit's message

ソフトウェア開発の仕事をしているsimotinといいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

/*~*/ コメントアウトを除去するコードをRubyで書いてみた

タイトルの通り、C言語系の複数行 /* ~ */ コメントを除去するコードを書いてみました。
Rubyで書いていますが状態遷移が基本になるのでどの言語でも同じように書けそうです。

# コメントアウトの除去
def delete_comment_out code
  status = :STATUS_WAIT_START_SLASH
  tmp = ""
  comment_out_code = ""
  code.each_char do |c|
    case status
    when :STATUS_WAIT_START_SLASH
      if (c == '/')
        tmp = c
        status = :STATUS_WAIT_START_ASTR
      else
        comment_out_code << c
      end
    when :STATUS_WAIT_START_ASTR
      if (c == '*')
        status = :STATUS_WAIT_END_ASTR
      else
        status = :STATUS_WAIT_START_SLASH
        comment_out_code << tmp
        comment_out_code << c
      end
    when :STATUS_WAIT_END_ASTR
      if (c == '*')
        status = :STATUS_WAIT_END_SLASH
      end
    when :STATUS_WAIT_END_SLASH
      if (c == '/')
        status = :STATUS_WAIT_START_SLASH
      end
    end
  end
  if status != :STATUS_WAIT_START_SLASH
    puts "status error"
  end
  comment_out_code
end

# テスト
code = File.read("test.c")
puts "--------------- before ------------------"
puts "#{code}"

comment_out_code = delete_comment_out(code)

puts "---------------  after ------------------"
puts "#{comment_out_code}"

元コード

#include <stdio.h>

// スラスラコメントは消えないよ
float func(void)
{
  float f = 1 * 2 / 3;
  int n = 1*2/3;

  /*
   * 複数行コメントも大丈夫
   */

   /* 掛け算・割り算も大丈夫 */
   return 1 * 2 / 3;
}

変換後コード

#include <stdio.h>


// スラスラコメントは消えないよ
float func(void)
{
  float f = 1 * 2 / 3;
  int n = 1*2/3;

  

   
   return 1 * 2 / 3;
}

状態遷移表

正規表現でもできると思っていたのですが、複数行でのマッチングがうまくできなかったのでコードで書いてみました。これくらい何も考えなくても10分くらいあれば書けるだろうと思っていたのですが、意外とパッと手が動かなかったので、まじめに状態遷移表を書いてからコードに落としてみました。

f:id:simotin13:20170513012803p:plain

感想

C言語の場合、コメント行の除去処理はプリプロセッサの仕事ですが、こうしてコードを書いてみると*/がない場合のエラー検出はコンパイル前に検出できますね。当たり前と言えば当たり前なんですが「コンパイルエラー」がどこで検出できるかまではあまり意識していないのでなんか新鮮な気持ちになりました。