`
oldrev
  • 浏览: 229908 次
  • 性别: Icon_minigender_1
  • 来自: 昆明
社区版块
存档分类
最新评论

简单的 C to D 转换 Ruby 脚本

阅读更多
今天晚上费了点脑筋写了一个简单的 C2D 转换脚本,大致实现了函数申明、全局变量、typedef、enum、struct 和数组的转换,但是还不支持预处理、union、调用约定等。

ruby 代码
 
  1. #!/bin/ruby  
  2. require 'rexml/document'  
  3.   
  4. #TODO:  
  5. # * 调用约定  
  6. # * union  
  7. # # 冲突关键字检查  
  8.   
  9. puts "c2d.rb 0.002 - A C to D Converter"  
  10. puts "Written by Wei Li <oldrev<at>gmail.com>"  
  11. puts "License: GPL"  
  12.   
  13. CFile = "hdr.c" #需要转换的 .h 或 .c 文件  
  14.   
  15. XmlFile = (CFile.map { |fn| fn += ".xml" }).to_s  
  16.   
  17. DVersion2 = false  
  18.   
  19. Cmd= "gccxml --gccxml-compiler \"gcc\" --gccxml-cxxflags \"-x c\" #{CFile} -fxml=#{XmlFile}"  
  20. puts Cmd  
  21. system Cmd  
  22. puts "GCCXML 转换完成"  
  23.   
  24. class Generator  
  25.   
  26.     def initialize(xml_file, writer)  
  27.         @writer = writer  
  28.         puts "正在加载 XML 文档"  
  29.         @xmlroot = REXML::Document.new(File.open(xml_file)).elements["GCC_XML"].elements  
  30.         builitin_ele = @xmlroot["File[contains(@name, 'gccxml_builtins.h')]"].attributes["id"]  
  31.   
  32.         #去掉 GCCXML 内置的东西  
  33.         @xmlroot.delete_all "*[@file='#{builitin_ele}']"  
  34.         puts "完成"  
  35.     end  
  36.   
  37.     def generate_linkage  
  38.         "extern(C)"  
  39.     end  
  40.   
  41.     def generate_fundamental_type(type_ele)  
  42.         case type_ele.attributes["name"]  
  43.         when "short int" :              "short"  
  44.         when "short unsigned int" :     "ushort"  
  45.         when "int" :                    "int"  
  46.         when "long int" :               "int"  
  47.         when "unsigned int" :           "uint"  
  48.         when "long unsigned int" :      "int"  
  49.         when "long long int" :          "long"  
  50.         when "long long unsigned int" : "ulong"  
  51.         when "float" :                  "float"  
  52.         when "double" :                 "double"  
  53.         when "char" :                   "char"  
  54.         when "unsigned char" :          "ubyte"  
  55.         when "signed char" :            "byte"  
  56.         when "void" :                   "void"  
  57.         when "wchar_t" :                if type_ele.attributes["size"] == "32" then "dchar" else "wchar" end  
  58.         when "signed wchar_t" :         if type_ele.attributes["size"] == "32" then "int" else "short" end  
  59.         when "unsigned wchar_t" :       if type_ele.attributes["size"] == "32" then "uint" else "ushort" end  
  60.         end  
  61.     end  
  62.   
  63.     def generate_type(type_id)  
  64.         ele = @xmlroot["*[@id='#{type_id}']"]  
  65.         case ele.name  
  66.   
  67.         when "FundamentalType" :  
  68.             generate_fundamental_type ele  
  69.   
  70.         when "Struct"  
  71.             @xmlroot["*[@id='#{type_id}']"].attributes["name"]  
  72.   
  73.         when "Typedef"  
  74.             @xmlroot["*[@id='#{type_id}']"].attributes["name"]  
  75.   
  76.         when "FunctionType"  
  77.             generate_function_type(ele)  
  78.   
  79.             #下面都是间接类型  
  80.         when "ArrayType"   
  81.             size = ele.attributes["max"].to_i - ele.attributes["min"].to_i + 1  
  82.             indirect_type = ele.attributes["type"]  
  83.             generate_type(indirect_type) + "[#{size}]"  
  84.   
  85.         when "PointerType"  
  86.             indirect_type = ele.attributes["type"]  
  87.             #函数指针需要特殊处理  
  88.             if @xmlroot["*[@id='#{indirect_type}']"].name == "FunctionType"   
  89.                 generate_type(indirect_type)   
  90.             else generate_type(indirect_type) + "*" end  
  91.   
  92.         when "CvQualifiedType"  
  93.             indirect_type = ele.attributes["type"]  
  94.             if @xmlroot["*[@id='#{indirect_type}']"].name == "FundamentalType"   
  95.                 "const " + generate_type(indirect_type)  
  96.             else  
  97.                 if DVersion2 : "const(" + generate_type(indirect_type) + ")"  
  98.                 else generate_type(indirect_type) end  
  99.             end  
  100.         end  
  101.     end  
  102.   
  103.     def generate_parameters(funcEle)  
  104.         params = []  
  105.         funcEle.elements.each("Argument") { |arg|   
  106.             type_id = arg.attributes["type"]  
  107.             type = generate_type(type_id)  
  108.             name = arg.attributes["name"]  
  109.             params << if name : "#{type} #{name}" else "#{type}" end  
  110.         }  
  111.         if params.length == 1 then return params[0]  
  112.         else   
  113.             return params.join(", ")  
  114.         end  
  115.     end  
  116.   
  117.     def generate_function_decl(e)  
  118.         return_type = generate_type(e.attributes["returns"])  
  119.         function_name = e.attributes["name"]  
  120.         parameters = generate_parameters(e)  
  121.         return "#{return_type} #{function_name}(#{parameters});\n"  
  122.     end  
  123.   
  124.     def generate_function_type(e)  
  125.         return_type = generate_type(e.attributes["returns"])  
  126.         parameters = generate_parameters(e)  
  127.         return "#{return_type} function(#{parameters})"  
  128.     end  
  129.   
  130.     def generate_fields(members)  
  131.         dcode = ""  
  132.         field_ids = []  
  133.         @xmlroot.each("Field") { |f| field_ids << f.attributes["id"] }  
  134.   
  135.         members.each { |mid|  
  136.             if field_ids.include? mid then  
  137.                 fe = @xmlroot["*[@id='#{mid}']"]  
  138.                 type = generate_type(fe.attributes["type"])  
  139.                 name = fe.attributes["name"]  
  140.                 dcode << "\t#{type} #{name};\n"  
  141.             end  
  142.         }  
  143.         return dcode  
  144.     end  
  145.   
  146.     def generate_struct(struct_ele)  
  147.         struct_name = struct_ele.attributes["name"]  
  148.         dcode = "\nstruct #{struct_name}\n"  
  149.         dcode << "{\n"  
  150.         dcode << generate_fields(struct_ele.attributes["members"].split(" ") )  
  151.         dcode << "};\n\n"  
  152.         return dcode   
  153.     end  
  154.   
  155.     def generate_typedef_decl(typedef_ele)  
  156.         typedef_name = typedef_ele.attributes["name"]  
  157.         type = generate_type(typedef_ele.attributes["type"])  
  158.         dcode = "alias #{type} #{typedef_name};\n"  
  159.         return dcode  
  160.     end  
  161.   
  162.     def generate_variable(var_ele)  
  163.         var_name = var_ele.attributes["name"]  
  164.         type = generate_type(var_ele.attributes["type"])  
  165.         init = var_ele.attributes["init"]  
  166.         dcode = "#{type} #{var_name}"  
  167.         if var_ele.attributes["extern"then dcode = "extern #{dcode}" end  
  168.         if init then dcode = "#{dcode} = #{init}" end  
  169.         dcode = "#{dcode};\n"  
  170.     end  
  171.   
  172.     def generate_enum(enum_ele)   
  173.         dcode = "enum " << enum_ele.attributes["name"] << " : int \n"  
  174.         dcode << "{\n"  
  175.         members = []  
  176.         enum_ele.elements.each("EnumValue") { |ev|  
  177.             evname = ev.attributes["name"]  
  178.             init = ev.attributes["init"]  
  179.             members << "\t#{evname} = #{init}"  
  180.         }  
  181.         if members.length <= 1  
  182.             dcode << members[0]  
  183.         else   
  184.             dcode << members.join(",\n")  
  185.         end  
  186.   
  187.         dcode << "\n}\n"  
  188.     end  
  189.   
  190.     def parse_node(node)  
  191.         @writer << case node.name  
  192.         when "Enumeration" : generate_enum node  
  193.         when "Function" : generate_function_decl node  
  194.         when "Struct" : generate_struct node  
  195.         when "Typedef" : generate_typedef_decl node  
  196.         when "Variable" : generate_variable node   
  197.         else ""  
  198.         end  
  199.     end  
  200.   
  201.     def parse_all_nodes  
  202.         @xmlroot.each { |node|   
  203.             parse_node node   
  204.         }  
  205.     end  
  206.   
  207. end #end of class Generator  
  208.   
  209. dcode = ""  
  210. gen = Generator.new( XmlFile, dcode)  
  211. gen.parse_all_nodes  
  212.   
  213. puts dcode  

我测试用的C语言头文件 hdr.c:
C代码
  1. #define DEFINE_CONST 123
  2. void foobar(double* x);
  3. double varD;
  4. unsigned long varL;
  5. wchar_t wc;
  6. struct Foo
  7. {
  8. int x;
  9. double y;
  10. long long z;
  11. };
  12. typedef Foo* FooPtr;
  13. typedef const Foo* ConstFooPtr;
  14. FooPtr myptr;
  15. Foo print(int x);
  16. Foo* print2(unsigned x, wchar_t y, long long z);
  17. Foo* print3(short x);
  18. Foo* print4(unsigned char x);
  19. void print5(unsigned x[]);
  20. void print6(FooPtr fp);
  21. void print7(const char* text);
  22. void print8(char** ppText);
  23. extern Foo g_foo;
  24. extern Foo g_foo10[10];
  25. extern int* g_pint20[20];
  26. static Foo s_foo;
  27. extern const double PI = 3.1415926;
  28. extern const char* TestString = "Hello";
  29. typedef void(*MyFuncPtr)(int x, long y, double z);
  30. enum MyEnum
  31. {
  32. Enum1 = 1,
  33. Enum2 = 2
  34. };

输出:
  1. c2d.rb 0.002 - A C to D Converter
  2. Written by Wei Li <oldrev<at>gmail.com>
  3. License: GPL
  4. gccxml --gccxml-compiler "gcc" --gccxml-cxxflags "-x c" hdr.c -fxml=hdr.c.xml
  5. GCCXML 转换完成
  6. 正在加载 XML 文档
  7. 完成
  8. enum MyEnum : int
  9. {
  10. Enum1 = 1,
  11. Enum2 = 2
  12. }
  13. alias void function(int, int, double) MyFuncPtr;
  14. const char* TestString = "Hello";
  15. const double PI = 3.14159260000000006840537025709636509418487548828e+0;
  16. Foo s_foo;
  17. extern int*[20] g_pint20;
  18. extern Foo[10] g_foo10;
  19. extern Foo g_foo;
  20. void print8(char** ppText);
  21. void print7(const char* text);
  22. void print6(FooPtr fp);
  23. void print5(uint* x);
  24. Foo* print4(ubyte x);
  25. Foo* print3(short x);
  26. Foo* print2(uint x, dchar y, long z);
  27. Foo print(int x);
  28. FooPtr myptr;
  29. alias Foo* ConstFooPtr;
  30. alias Foo* FooPtr;
  31. struct Foo
  32. {
  33. int x;
  34. double y;
  35. long z;
  36. };
  37. dchar wc;
  38. int varL;
  39. double varD;
  40. void foobar(double* x);

Requirements

  1. Ruby1.8: 废话
  2. GCCXML: Linux 直接使用包管理系统安装,Windows 可到 www.gccxml.org 下载安装程序

Have fun!
分享到:
评论
9 楼 oldrev 2007-11-03  
官网那个 htod 不开源,只能运行于Windows,这个Ruby程序可以作为一个补充。
8 楼 qiezi 2007-11-03  
头文件转换是比较麻烦的,工具一般不能处理宏函数,这在C里面是很普遍的。而且工具通常需要把宏展开才能得到结果,展开后宏就没剩下原来的信息了。
7 楼 oldrev 2007-11-03  
Ruby 脚本没法做成exe。
Ruby 在大多数 Linux、Mac OSX 都是系统内置的,这个脚本就是可执行文件。Windows 使用者可以自己去下载 gccxml/ruby 然后再设置路径,如果有耐心的话。
6 楼 tuja 2007-11-03  
最好做成可执行文件, 同时用ruby和D的恐怕不是很多
5 楼 oldrev 2007-11-02  
Version 0.005,能够转换 #define 定义的常量了。

下载:
http://dotmars.googlecode.com/svn/trunk/tools/htd/htd.rb
4 楼 oldrev 2007-10-30  
0.004 发布,转换功能基本可用,不支持C++,需要 GCCXML和Ruby1.8。

尚未实现的功能:
* 预处理常量和宏
* 非C调用约定
* 自动生成多模块
* 对齐
* D2

下载:
http://dotmars.googlecode.com/svn/trunk/tools/htd/htd.rb
3 楼 oldrev 2007-10-26  
目前只差宏、预处理常量和调用约定了。
2 楼 ideage 2007-10-25  
不错!支持!
1 楼 oldrev 2007-10-25  
恩,预计这个星期以内就完全可以使用了。

相关推荐

Global site tag (gtag.js) - Google Analytics