RubyでC++enumを文字列で返す関数を自動生成する

By | 2012/11/16

C++でenumの名前をそのまま文字列にしたいことがたまにある。テンプレートとか駆使してなんとか楽できないかと思ったけど思いつかず。愚直にswitchで文字列を返す関数を作ることにした。しかし手作業はあり得ないと思ったのでRubyのお世話に。

(enumの名前,enumのメンバを入れる配列)の配列を作って元ファイルから取り出して適当に書き出しています。
処理の流れ

  1. 元のファイルを読み込む(MakeEnum2StringFile())
  2. 正規表現でマッチするenum文字を見つける(MakeEnum2StringFile())
  3. 正規表現でマッチするメンバを集める(GetElements())
  4. 文字列として返す関数を作りながらファイルに書き込む(MakeFile())

rubyコード

# 特定のファイルにあるenumをすべて探し出して文字列として返す関数を作る
# --------------------------------------------------
def GetElements(f)
     elements = []

     while l=f.gets
          s = l.gsub(/(\t|\s|\n)/, "") # タブ、空白、改行を消す
          break if s=="};"

          s = s.gsub(/(,|(#\w+)|(\/\/.*))/, "") # ,(コロン)、#から始まる行、コメントを消す(/**/タイプのコメントは未対応)
          next if s=="" # 空白行は飛ばす
          s = s.gsub(/=\w+/, "") # XXX=YYY みたいなやつは=以降を消す

          elements << s
     end

     elements = elements.uniq
     return elements
end

# --------------------------------------------------
def MakeFile(output_filename, enums, namespace)

     File.open(output_filename, "w"){ |f|
               f.puts "#ifndef ENUM2STRING_H"
               f.puts "#define ENUM2STRING_H"
               f.puts ""
               f.puts "namespace #{namespace}{"
          enums.each do |e|
               f.puts ""
               f.puts "inline const char* Enum2String(#{e.title} e){"
               f.puts "     switch(e){"
               e.elements.each do |element|
               f.puts "     case #{element}: return \"#{element}\";"
               end
               f.puts "     default: ASSERT(false); return NULL;"
               f.puts "     }"
               f.puts "}"
               f.puts ""
          end
               f.puts "};"
               f.puts ""
               f.puts "#endif ENUM2STRING_H"
     }
end

# --------------------------------------------------
def MakeEnum2StringFile(input_filename, output_filename, namespace)

     enums = []
     File.open(input_filename, "r"){ |f|
          while l=f.gets

               # enum を見つける
               title = l.scan(/enum\s+(\w+)\{/) #enum[空白][タイトル]{
               next if title.size==0

               # enum の要素を取り出す
               elements = GetElements(f)

               enums     << Enum.new(title, elements)
          end
     }

     # enum値を文字列で返す関数群ファイルを作る
     MakeFile(output_filename, enums, namespace)
end

# main
# --------------------------------------------------
Enum = Struct.new(:title, :elements)

MakeEnum2StringFile("sdk/inc/graphics/Types.h", "sdk/inc/graphics/TypesEnum2String.h", "gfx")


コメントを残す

メールアドレスが公開されることはありません。