1module DL 2 # Methods for parsing C struct and C prototype signatures. 3 module CParser 4 # Parses a C struct's members 5 # 6 # Example: 7 # 8 # parse_struct_signature(['int i', 'char c']) 9 # => [[DL::TYPE_INT, DL::TYPE_CHAR], ["i", "c"]] 10 # 11 def parse_struct_signature(signature, tymap=nil) 12 if( signature.is_a?(String) ) 13 signature = signature.split(/\s*,\s*/) 14 end 15 mems = [] 16 tys = [] 17 signature.each{|msig| 18 tks = msig.split(/\s+(\*)?/) 19 ty = tks[0..-2].join(" ") 20 member = tks[-1] 21 22 case ty 23 when /\[(\d+)\]/ 24 n = $1.to_i 25 ty.gsub!(/\s*\[\d+\]/,"") 26 ty = [ty, n] 27 when /\[\]/ 28 ty.gsub!(/\s*\[\]/, "*") 29 end 30 31 case member 32 when /\[(\d+)\]/ 33 ty = [ty, $1.to_i] 34 member.gsub!(/\s*\[\d+\]/,"") 35 when /\[\]/ 36 ty = ty + "*" 37 member.gsub!(/\s*\[\]/, "") 38 end 39 40 mems.push(member) 41 tys.push(parse_ctype(ty,tymap)) 42 } 43 return tys, mems 44 end 45 46 # Parses a C prototype signature 47 # 48 # Example: 49 # 50 # include DL::CParser 51 # => Object 52 # 53 # parse_signature('double sum(double, double)') 54 # => ["sum", DL::TYPE_DOUBLE, [DL::TYPE_DOUBLE, DL::TYPE_DOUBLE]] 55 # 56 def parse_signature(signature, tymap=nil) 57 tymap ||= {} 58 signature = signature.gsub(/\s+/, " ").strip 59 case signature 60 when /^([\w@\*\s]+)\(([\w\*\s\,\[\]]*)\)$/ 61 ret = $1 62 (args = $2).strip! 63 ret = ret.split(/\s+/) 64 args = args.split(/\s*,\s*/) 65 func = ret.pop 66 if( func =~ /^\*/ ) 67 func.gsub!(/^\*+/,"") 68 ret.push("*") 69 end 70 ret = ret.join(" ") 71 return [func, parse_ctype(ret, tymap), args.collect{|arg| parse_ctype(arg, tymap)}] 72 else 73 raise(RuntimeError,"can't parse the function prototype: #{signature}") 74 end 75 end 76 77 # Given a String of C type +ty+, return the corresponding DL constant. 78 # 79 # +ty+ can also accept an Array of C type Strings, and will returned in a 80 # corresponding Array. 81 # 82 # If Hash +tymap+ is provided, +ty+ is expected to be the key, and the 83 # value will be the C type to be looked up. 84 # 85 # Example: 86 # 87 # parse_ctype('int') 88 # => DL::TYPE_INT 89 # 90 # parse_ctype('double') 91 # => DL::TYPE_DOUBLE 92 # 93 # parse_ctype('unsigned char') 94 # => -DL::TYPE_CHAR 95 # 96 def parse_ctype(ty, tymap=nil) 97 tymap ||= {} 98 case ty 99 when Array 100 return [parse_ctype(ty[0], tymap), ty[1]] 101 when "void" 102 return TYPE_VOID 103 when "char" 104 return TYPE_CHAR 105 when "unsigned char" 106 return -TYPE_CHAR 107 when "short" 108 return TYPE_SHORT 109 when "unsigned short" 110 return -TYPE_SHORT 111 when "int" 112 return TYPE_INT 113 when "unsigned int", 'uint' 114 return -TYPE_INT 115 when "long" 116 return TYPE_LONG 117 when "unsigned long" 118 return -TYPE_LONG 119 when "long long" 120 if( defined?(TYPE_LONG_LONG) ) 121 return TYPE_LONG_LONG 122 else 123 raise(RuntimeError, "unsupported type: #{ty}") 124 end 125 when "unsigned long long" 126 if( defined?(TYPE_LONG_LONG) ) 127 return -TYPE_LONG_LONG 128 else 129 raise(RuntimeError, "unsupported type: #{ty}") 130 end 131 when "float" 132 return TYPE_FLOAT 133 when "double" 134 return TYPE_DOUBLE 135 when "size_t" 136 return TYPE_SIZE_T 137 when "ssize_t" 138 return TYPE_SSIZE_T 139 when "ptrdiff_t" 140 return TYPE_PTRDIFF_T 141 when "intptr_t" 142 return TYPE_INTPTR_T 143 when "uintptr_t" 144 return TYPE_UINTPTR_T 145 when /\*/, /\[\s*\]/ 146 return TYPE_VOIDP 147 else 148 if( tymap[ty] ) 149 return parse_ctype(tymap[ty], tymap) 150 else 151 raise(DLError, "unknown type: #{ty}") 152 end 153 end 154 end 155 end 156end 157