Get functions names with regex

A

Ahmet Kilic

I have text file like this,

str = "function ExecMain.GetApiErrorMessage(ApiErrCode :DWORD) :String;
var
Buf: array[0..511] of Char;
MsgCnt :DWORD;
begin
function THandle.SetPrivilege(PrivilegeName: String;
Enable: Boolean): Boolean;
var
tpPrev,
tp : TTokenPrivileges;
token : THandle;
dwRetLen : DWord;
begin
function Privileges.SetPrivilege(PrivilegeName: String;
Enable: Boolean): Boolean;
var
tpPrev,
tp : Privileges;
token : THandleTest;
dwRetLen : DWord;
begin"

str =~ /(function)\s+(\w+)(.*);/
func_names = $1
puts "#{$'}"
while(str) # while(true)
str = $' #second function
str =~ /:(\w+);/m
args = $1
# str.scan(/:(\w+);/m) do |d|
# puts $1 # private method error
# end
if args == func_names
puts func_names
end
puts "-----------------------------"
puts "#{$'}"
end

I am writing this script for getting the function names and args names.
but there is some rules:
1- if I want to scan one function name, next time I need scan second
function name.(because I need which args belongs to which functions
name)
2- If args names same as functions names I want to print the function
name.

with this code I am not get the args name.
please help me.
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

I have text file like this,

str = "function ExecMain.GetApiErrorMessage(ApiErrCode :DWORD) :String;
var
Buf: array[0..511] of Char;
MsgCnt :DWORD;
begin
function THandle.SetPrivilege(PrivilegeName: String;
Enable: Boolean): Boolean;
var
tpPrev,
tp : TTokenPrivileges;
token : THandle;
dwRetLen : DWord;
begin
function Privileges.SetPrivilege(PrivilegeName: String;
Enable: Boolean): Boolean;
var
tpPrev,
tp : Privileges;
token : THandleTest;
dwRetLen : DWord;
begin"

str =~ /(function)\s+(\w+)(.*);/
func_names = $1
puts "#{$'}"
while(str) # while(true)
str = $' #second function
str =~ /:(\w+);/m
args = $1
# str.scan(/:(\w+);/m) do |d|
# puts $1 # private method error
# end
if args == func_names
puts func_names
end
puts "-----------------------------"
puts "#{$'}"
end

I am writing this script for getting the function names and args names.
but there is some rules:
1- if I want to scan one function name, next time I need scan second
function name.(because I need which args belongs to which functions
name)
2- If args names same as functions names I want to print the function
name.

with this code I am not get the args name.
please help me.
#try this code (I'm on 1.8.6)


#a function declaration that was parsed out of some text
class ParsedFunction

attr_accessor :name , :args

#expects args to be in format [[name,type],[name,type]]
def initialize( name , *args )
@name , @args = name , *args
end

#call like this: funct.each_arg{|arg_name,arg_type| ... }
def each_arg
args.each do |arg|
yield *arg
end
end

def to_s
"function #{name}( #{args.map{|arg| arg.join(': ') }.join('; ')} )"
end
end

functs = Array.new

str.scan(/^\s*function\s*([^(]+)\(([^)]+)/).map do |name,args|
name.gsub!(/\s/,'')
args.gsub!(/\s/,'')
functs << ParsedFunction.new( name , args.split(/;/).map{|arg|
arg.split(/:/) } )
end

puts "THE FUNCTIONS FOUND WERE: \n\n"
functs.each do |f|
puts "signature: #{f}"
puts "name: #{f.name}"
puts "number of args: #{f.args.size}"
puts "list of args:"
f.each_arg{|arg_name,arg_type| puts " #{arg_name} : #{arg_type}" }
puts
end

__END__
I get the following output:

THE FUNCTIONS FOUND WERE:

signature: function ExecMain.GetApiErrorMessage( ApiErrCode: DWORD )
name: ExecMain.GetApiErrorMessage
number of args: 1
list of args:
ApiErrCode : DWORD

signature: function THandle.SetPrivilege( PrivilegeName: String; Enable:
Boolean )
name: THandle.SetPrivilege
number of args: 2
list of args:
PrivilegeName : String
Enable : Boolean

signature: function Privileges.SetPrivilege( PrivilegeName: String; Enable:
Boolean )
name: Privileges.SetPrivilege
number of args: 2
list of args:
PrivilegeName : String
Enable : Boolean
 
A

Ahmet Kilic

Thank you very much,
I am making customize the code but when I change this part from
str.scan(/^\s*function\s*([^(]+)\(([^)]+)/).map do |name,args|
to
/procedure|function\s+(\w+)([^\s(]+)\s*\(([^)]+)\)\s*:\s*(\S+)\s*;\s*^\s*var\s*$(.*?)^begin/xm

i could`t get the args name.
an the results like this:

THE FUNCTIONS FOUND WERE:

signature: function ExecMain( .GetApiErrorMessage )
name: ExecMain
number of args: 1
list of args:
.GetApiErrorMessage :

signature: function THandle( .SetPrivilege )
name: THandle
number of args: 1
list of args:
.SetPrivilege :

signature: function Privileges( .SetPrivilege )
name: Privileges
number of args: 1
list of args:
.SetPrivilege :

I think something changing somewhere..
 
R

Robert Klemme

functs = Array.new

str.scan(/^\s*function\s*([^(]+)\(([^)]+)/).map do |name,args|
name.gsub!(/\s/,'')
args.gsub!(/\s/,'')
functs << ParsedFunction.new( name , args.split(/;/).map{|arg|
arg.split(/:/) } )
end

Either you should not be using #map above or assign the result of #map
to functs. A #map without using the result is pretty useless.

But definitively #scan is the right tool for the job. If only printing
of function names and arguments is interesting that could be done inside
the #scan body as well avoiding a second pass.

Kind regards

robert
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

Thank you very much,
I am making customize the code but when I change this part from
str.scan(/^\s*function\s*([^(]+)\(([^)]+)/).map do |name,args|
to

/procedure|function\s+(\w+)([^\s(]+)\s*\(([^)]+)\)\s*:\s*(\S+)\s*;\s*^\s*var\s*$(.*?)^begin/xm
I don't know what you are looking for exactly, but it looks like
procedure|functions should be grouped. Also, all your capture groups are
going to get passed into the block, so for each of them, you need a
variable. Any groups that you don't want passed in, you should make into a
non capture group by placing ?: after the opening of the group, like this
(?:)

To see what is going on, you can have the block accept a variable list of
arguments, then print that out to see what was passed in, something like
this:

"ab cdef".scan(/(b)(\s*)(?:c)de(f)/).each do |*args|
p *args
end

Which would print out ["b", " ", "f"] Then you can go and change your
groups around, and see how that affects it.


functs = Array.new

str.scan(/^\s*function\s*([^(]+)\(([^)]+)/).map do |name,args|
name.gsub!(/\s/,'')
args.gsub!(/\s/,'')
functs << ParsedFunction.new( name , args.split(/;/).map{|arg|
arg.split(/:/) } )
end

Either you should not be using #map above or assign the result of #map to
functs. A #map without using the result is pretty useless.

But definitively #scan is the right tool for the job. If only printing of
function names and arguments is interesting that could be done inside the
#scan body as well avoiding a second pass.

Kind regards

robert
Yes, that should be replaced with "each". I initially had it like this

functs = str.scan(/^\s*function\s*([^(]+)\(([^)]+)/).map do |name,args|
name.gsub!(/\s/,'')
args.gsub!(/\s/,'')
ParsedFunction.new( name , args.split(/;/).map{|arg| arg.split(/:/) } )
end

But I thought it might be easier to follow if I separated the functs
variable. When I did that, I should have also switched map to each.
 
A

Ahmet Kilic

To see what is going on, you can have the block accept a variable list
of
arguments, then print that out to see what was passed in, something like
this:

"ab cdef".scan(/(b)(\s*)(?:c)de(f)/).each do |*args|
p *args
end

Which would print out ["b", " ", "f"] Then you can go and change your
groups around, and see how that affects it.
functs = str.scan(/^\s*function\s*([^(]+)\(([^)]+)/).map do |name,args|
name.gsub!(/\s/,'')
args.gsub!(/\s/,'')
ParsedFunction.new( name , args.split(/;/).map{|arg| arg.split(/:/) }
)

Thanks I think it is clear now.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,828
Latest member
LauraCastr

Latest Threads

Top