Is there a simple way to convert C++ enum to string?

后端 未结 30 2820
我在风中等你
我在风中等你 2020-11-22 10:37

Suppose we have some named enums:

enum MyEnum {
      FOO,
      BAR = 0x50
};

What I googled for is a script (any language) that scans all

30条回答
  •  面向向阳花
    2020-11-22 11:10

    The following ruby script attempts to parse the headers and builts the required sources alongside the original headers.

    #! /usr/bin/env ruby
    
    # Let's "parse" the headers
    # Note that using a regular expression is rather fragile
    # and may break on some inputs
    
    GLOBS = [
      "toto/*.h",
      "tutu/*.h",
      "tutu/*.hxx"
    ]
    
    enums = {}
    GLOBS.each { |glob|
      Dir[glob].each { |header|
        enums[header] = File.open(header, 'rb') { |f|
          f.read
        }.scan(/enum\s+(\w+)\s+\{\s*([^}]+?)\s*\}/m).collect { |enum_name, enum_key_and_values|
          [
            enum_name, enum_key_and_values.split(/\s*,\s*/).collect { |enum_key_and_value|
              enum_key_and_value.split(/\s*=\s*/).first
            }
          ]
        }
      }
    }
    
    
    # Now we build a .h and .cpp alongside the parsed headers
    # using the template engine provided with ruby
    require 'erb'
    
    template_h = ERB.new <<-EOS
    #ifndef <%= enum_name %>_to_string_h_
    #define <%= enum_name %>_to_string_h_ 1
    
    #include "<%= header %>"
    char* enum_to_string(<%= enum_name %> e);
    
    #endif
    EOS
    
    template_cpp = ERB.new <<-EOS
    #include "<%= enum_name %>_to_string.h"
    
    char* enum_to_string(<%= enum_name %> e)
    {
      switch (e)
      {<% enum_keys.each do |enum_key| %>
        case <%= enum_key %>: return "<%= enum_key %>";<% end %>
        default: return "INVALID <%= enum_name %> VALUE";
      }
    }
    EOS
    
    enums.each { |header, enum_name_and_keys|
      enum_name_and_keys.each { |enum_name, enum_keys|
        File.open("#{File.dirname(header)}/#{enum_name}_to_string.h", 'wb') { |built_h|
          built_h.write(template_h.result(binding))
        }
    
        File.open("#{File.dirname(header)}/#{enum_name}_to_string.cpp", 'wb') { |built_cpp|
          built_cpp.write(template_cpp.result(binding))
        }
      }
    }
    

    Using regular expressions makes this "parser" quite fragile, it may not be able to handle your specific headers gracefully.

    Let's say you have a header toto/a.h, containing definitions for enums MyEnum and MyEnum2. The script will build:

    toto/MyEnum_to_string.h
    toto/MyEnum_to_string.cpp
    toto/MyEnum2_to_string.h
    toto/MyEnum2_to_string.cpp
    

    More robust solutions would be:

    • Build all sources defining enums and their operations from another source. This means you'll define your enums in a XML/YML/whatever file which is much easier to parse than C/C++.
    • Use a real compiler such as suggested by Avdi.
    • Use preprocessor macros with or without templates.

提交回复
热议问题