# Eliminate array size arguments
# May 13, 2002 T. Horinouchi
#
# Usage:
# % ruby generate_new_rbdcl.rb proto_files
# where files are grph2_uvpack.fp math2_fftlib.fb etc (in the proto directory)
class Variable
def initialize(decl)
name, *tmp = decl.split.reverse
tmp.reverse!
attr = (tmp[-1] =~ /^[a-z]+$/ ? tmp.pop : "i")
ary = (tmp[-1] =~ /^\((.*)\)/ ? (tmp.pop; $1.downcase) : false)
vtype = tmp.pop
if (/(\d+)|\*\((.*)\)/ =~ vtype)
charlen = ($1||$2).downcase # may be charcter length
vtype = vtype.scan(/\w+/)[0]
else
charlen = nil
end
@name = name.downcase
@attr = attr
@ary = ary
@vtype = vtype.downcase
end
attr_reader(:name, :attr, :ary, :vtype)
end
def pre_filter(decl)
case $method_name
when /(^ud|^ue)/
# replace MX with NX
decl.gsub!('MX','NX')
when /^ug/
# replace MU & MV with NX
decl.gsub!(/(MU|MV)/,'NX')
end
decl
end
def extract_args(proto)
args_org = []
while ( decl = proto.gets )
break if decl =~ /^ *\)$/
decl = pre_filter(decl)
if ( decl !~ /^\s*$/ )
print decl if $DEBUG
var = Variable.new(decl)
p var if var.ary if $DEBUG
if var.attr != "o" && var.attr != "t"
args_org.push(var)
else
end
end
end
args_org
end
def has_array?( args )
args.each do |v|
return true if v.ary
end
false
end
def new_args( args_org )
del_argname = []
args_org.each do |v|
if ( (shape = v.ary) )
shape = shape.split(',')
shape.each do |lendef|
lpos = lendef.index(/([a-z]\w*)/)
m = $1
if ( lpos )
lpos2 = lendef.index(/([a-z]\w*)/,lpos+m.length)
if (!lpos2)
# to be deleted only when unambiguous
del_argname.push(m) if m && !del_argname.include?(m)
end
end
end
end
end
args_new = args_org.clone
del_argname.each do |nm|
args_new.delete_if {|v|
v.name == nm
}
end
print " ORG: ", args_org.collect{|i| i.name}.join(','),"\n" if $DEBUG
print " NEW: ", args_new.collect{|i| i.name}.join(','),"\n" if $DEBUG
print " args deleted: ",del_argname.join(','),"\n" if $DEBUG
[args_new, del_argname]
end
def new_def( args_org, args_new, del_argname )
method_def = <<-EOS
alias __#{$method_name} #{$method_name}
def #{$method_name}( #{args_new.collect{|i| i.name}.join(',')} )
EOS
method_def.concat( del_arg_deriv( args_new, del_argname ) )
args_org_names = args_org.collect{|arg| arg.name}
method_def.concat( check_array_size( args_new, args_org_names ) )
method_def.concat( <<-EOS
#< call the original method >
__#{$method_name}( #{args_org.collect{|i| i.name}.join(',')} )
end
module_function :#{$method_name}, :__#{$method_name}
private_class_method :__#{$method_name}
EOS
)
#print '*** ',method_def
method_def
end
#def wrap_in_rundef_rescue(
# if ( #{v.name}.is_a(Float) && x == glrget("RMISS") )
#end
def del_arg_deriv( args_new, del_argname )
deriv = ""
first = true
del_argname.each do |nm|
ary = []
args_new.each do |v|
if v.ary && v.ary =~ /\W*#{nm}\W*/
ary.push( [ v.name, inv_deriv(nm, v.ary, v.name) ] )
if (!possibly_rundef?(nm, v.name))
break
end
end
end
if(first)
deriv = <<-EOS
#< extract array size(s) (which was(were) formerly an argument(s)) >
EOS
first = false
end
deriv.concat( recursive_join( ary ) )
end
deriv
end
def possibly_rundef?(argname, varname)
case $method_name
when /(^usgrph|^usspnt)/
if( argname == 'n' && varname == 'x' )
return true
elsif ( argname == nil )
return true
end
when /(^uulin|^uumrk|^uv|^uh)/
if ( argname == 'n' &&
( varname == 'upx' || varname == 'upy' ||
varname == 'upx1' || varname == 'upx2' ||
varname == 'upy1' || varname == 'upy2' ) )
return true
elsif ( argname == nil )
return true
end
end
false
end
def recursive_join( ary )
first = ary.shift
if( ary.length > 0)
str = <<-EOS
if ! ( #{first[0]} == nil || #{first[0]}.is_a?(Float) && lreq( #{first[0]}, glrget("RUNDEF") ) )
#{first[1].gsub(/^/," ").chop}
else
EOS
str += <<-EOS
#{first[0]} = glrget("RUNDEF") if ( #{first[0]} == nil )
#{recursive_join(ary).gsub(/^/," ").chop}
end
EOS
else
first[1]
end
end
def inv_arithm(lendef, varname)
case lendef
when varname
form = "LEN"
when /^(\w+) *\* *#{varname}$/
form = "LEN / #{$1}"
when /^#{varname} *\/ *(\w+)$/
form = "LEN * #{$1}"
when /^#{varname} *\+ *(\w+)$/
form = "LEN - #{$1}"
when /^\(*(\w+) *\* *#{varname} *\+ *(\w+)\)*$/
form = "( LEN - #{$2} ) / #{$1}"
else
raise 'unsuppoerted dimension specification : '+lendef
end
form
end
def inv_deriv(argname, shape, aryname)
deriv = ""
shape = shape.split(',')
multiD = ( shape.length > 1 )
shape.each_index do |i|
if (lendef=shape[i]) =~ /\W*#{argname}\W*/
idim = i
form = inv_arithm( lendef, argname )
form.sub!('LEN',"len_#{aryname}_#{idim}")
if multiD
deriv = <<-EOS
if ( not_nary(#{aryname}) || (#{aryname}.rank < #{idim+1}) )
raise "#{aryname} must be a NArray of rank == #{shape.length}"
end
len_#{aryname}_#{idim} = #{aryname}.shape[#{idim}]
EOS
else
deriv = <<-EOS
len_#{aryname}_#{idim} = #{aryname}.length
EOS
end
deriv.concat( <<-EOS
#{argname} = #{form}
EOS
)
print deriv if $DEBUG
break
end
end
deriv
end
def aster2dimlen_if_possible( varname, dimlen )
if $method_name =~ /(^rvmax|^rvmin)/ && varname == 'rx'
dimlen.replace('(len=1; ns.each{|i| len*=i}; len)')
true
else
raise $!
end
end
def consist_of_names?(str, names)
ary = str.split(/\W/).uniq
names.each{|str| ary.delete(str)}
ary.each do |str|
return false if (/^\d*$/ !~ str)
end
true
end
def check_array_size( args_new, args_org_names )
body = <<-EOS
#< check array size(s) >
EOS
args_new.each do |v|
if ( v.ary )
shape = v.ary.split(',')
if ( shape.length == 1 )
arylen_replaced = false
if ( shape[0] == '*' )
begin
raise "Array #{v.name} is declared using *"
rescue
arylen_replaced = aster2dimlen_if_possible( v.name, shape[0] )
end
end
if possibly_rundef?(nil, v.name)
ins = "\\\n #{v.name}!=nil && !( #{v.name}.is_a?(Float) && lreq(#{v.name},glrget(\"RUNDEF\")) ) && "
else
ins = ""
end
if arylen_replaced || consist_of_names?(shape[0], args_org_names )
body.concat( <<-EOS
raise "Invalid array length: #{v.name}.length != #{shape[0]}" if #{ins}#{v.name}.length != (#{shape[0]})
EOS
)
end
else
shape.each_index do |i|
if ( shape[i] == '*' )
raise "Array #{v.name}'s #{i}-th dim is declared using *"
end
body.concat( <<-EOS
raise "Invalid array shape: #{v.name}.shape[#{i}] != #{shape[i]}" if #{v.name}.shape[#{i}] != (#{shape[i]})
EOS
)
end
end
end
end
body
end
def head
f = File.open('dcl_rb_heading')
heading = f .readlines
f.close
heading
end
def close
return <<-EOS
end
end
EOS
end
def post_filter( ndf )
if $method_name == 'udcntz'
ndf.sub!(/,nbr2/,'')
add = <<-EOS
# derivation of nbr2 is provied aditionally in the method post_filter:
nbr2 = (nx+2)*(ny+2)*6/32+4
EOS
ndf =~ /(^ *\#.*check array size.*$)/
ndf[$1] = add + $1
end
end
def delete_comment(src) # [ruby-list:32030] [ruby-list:32049]
src.gsub(%r@ ([\'\"])(\\.|.)*?\1
| (/\*.*?\*/)
| (//)[^\n]*$
@mx) {
if $3
s = $3.delete("^\n")
s = ' ' if s.empty?
s
elsif $4
''
else
$&
end
}
end
##################### (main) ###########################
require "tempfile"
files = ARGV
ofilename = "src/lib/dcl.rb"
ofile = open( ofilename, "w+" )
ofile.puts( head() )
for f in files
print "processing file #{f}\n"
#proto = open("| cat #{f} | gcc -E -", "r+")
#proto.close_write
fl = File.open(f)
proto = Tempfile.new('proto', '.')
proto.print( delete_comment(fl.read) )
proto.sync
proto.rewind
fl.close
while ( line = proto.gets )
case line
when /^ *SUBROUTINE *(\w+)|^ *\w+ *FUNCTION *(\w+)/
$method_name = ( $1 || $2 ).downcase
print $method_name+"\n" if $DEBUG
args_org = extract_args(proto)
if ( has_array?(args_org) )
# redefine the method
args_new, del_argname = new_args( args_org )
ndf = new_def( args_org, args_new, del_argname )
post_filter( ndf )
ofile.puts( ndf )
end
when /^#if *DCLVER *([<=>]+) *(\d\d)/
op = $1
ver = "'"+$2[0..0]+'.'+$2[1..1]+"'" # "'5.2'" etc
ofile.print(" if DCLVERSION #{op} #{ver}\n")
when /^#endif/
ofile.print(" end\n\n")
end
end
proto.close
end
ofile.puts( close() )
ofile.close
print "generated the DCL module file #{ofilename}\n"
syntax highlighted by Code2HTML, v. 0.9.1