From: Alexander Kellett Date: 2005-02-14T19:35:56+09:00 Subject: Re: [ANN] ruby-ast-c++ 0.0.1 --Apple-Mail-4--926366406 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed On Feb 14, 2005, at 11:05 AM, Phil Tomson wrote: > In article , > Alexander Kellett wrote: >> over the last few hours i finally got around to writing >> an elsa based c++ "parsetree" style library for ruby. >> >> an example usage is parsing of the Qt header qstring.h, and >> listing of all the method names defined in QString. > > Definately interested. What is elsa? http://www.cs.berkeley.edu/~smcpeak/elkhound/sources/elsa/index.html i just wrote a simple wrapper that parses the generated ast. with this its pretty simple to get out needed information. wrapper is attached, its really trivial :) --Apple-Mail-4--926366406 Content-Transfer-Encoding: 7bit Content-Type: application/octet-stream; x-unix-mode=0644; name="t.rb" Content-Disposition: attachment; filename=t.rb # g++ -E /Developer/qt/include/QtCore/qstring.h -I /Developer/qt/include/Qt -I /usr/include/gcc/darwin/3.3/ >! qstring.h.out %w(pp tempfile).each{|r|require r} ast_cache_fn = "/tmp/qtr4_ast_raw.cache" ast_tree_cache_fn = "/tmp/qtr4_ast_tree.cache" should_parse = false should_dissect = false if should_parse blacklist_headers = %w(qatomic) sect, src = nil, "" IO.read("qstring.h.out").each_line { |l| if l =~ /^# \d+? "(.*?)"/ sect = $1 else src << l + "\n" unless sect =~ /#{blacklist_headers.join "|"}/ end } tf = Tempfile.new "qtr4_postproc" tf.write src tf.close system "./ccparse -tr printTypedAST #{tf.path} > #{ast_cache_fn}" end objs = nil if should_dissect old_indent = 0 ast = IO.read ast_cache_fn obj, stack = [], [] objs = obj ast.each_line { |l| l =~ /^(\s*)/ indent = $1.length if indent > old_indent new_obj = [l] stack << new_obj obj << new_obj obj = new_obj elsif indent == old_indent obj << l elsif indent < old_indent ((old_indent - indent) / 2).times { obj = stack.pop } obj = stack.last || objs obj << l end old_indent = indent } File.open(ast_tree_cache_fn, "w") { |file| file.print Marshal.dump(objs) } else File.open(ast_tree_cache_fn, "r") { |file| objs = Marshal.load(file) } end class Array def down re objs = self objs.each_with_index { |obj,idx| next unless obj.is_a? String return objs[idx+1] if obj =~ re } nil end def matching re objs = self objs.each_with_index { |obj,idx| next unless obj.is_a? String yield objs[idx+1], obj if obj =~ re } end end method_list = [] objs.down(/tree = TranslationUnit/).down(/topForms:/).matching(/topForms\[.*?\] = TF_decl/) { |top_form,| top_form.down(/decl =/).matching(/spec = TS_classSpec/) { |class_spec,| class_name_string = class_spec.down(/name = /).grep(/name = /).first class_name = class_name_string.chomp.slice(class_name_string.index("=") + 2..-1) next unless class_name == "QString" class_spec.down(/members = MemberList/).down(/list:/).matching(/list\[.*?\]/) { |decl, line| next if line =~ /(MR_access|MR_func)/ decllist = decl.down(/d = Declaration/).down(/decllist:/) next if decllist.nil? decllist.matching(/decllist\[.*?\]/) { |fdecl,| func_spec = fdecl.down(/decl = D_func/) next if func_spec.nil? method_spec = func_spec.down(/base =/) next if method_spec.grep(/name = /).empty? method_name_string = method_spec.down(/name = /).grep(/(name|fakeName) = /).first method_name = method_name_string.chomp.slice(method_name_string.index("=") + 2..-1) method_list << method_name } } } } p method_list --Apple-Mail-4--926366406 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed Alex --Apple-Mail-4--926366406--