2016-08-11 2 views
1

Fortran 프로 시저의 어떤 인수가 프로 시저 내에 정의되어 있는지 확인하는 데 사용할 수있는 도구가 있습니까? 변수가 할당 문 (또는 동급 문)의 왼쪽에 사용되는지 단순히 확인하는 어휘 분석기와 같은 것을 의미합니다. 인 텐트 (in)가 인수로 지정되면 컴파일러가 수행하는 검사와 비슷한 점이 있습니다.포트란 절차가 인수를 수정하는지 확인하는 도구가 있습니까?

대부분 Fortran 77 표준 (의도가 지정되지 않음)으로 작성된 코드와 수백 개의 인수가있는 서브 루틴이 있는데,이 서브 루틴 중 일부는 각각 5000 줄 이상의 코드 행으로 확장됩니다. 코드의 일부를 수정하고 긴 서브 루틴을 다시 작성하고 싶습니다. 나는 변화하는 주장을 추적 할 수 있다면 쉽게 될 것이라고 생각한다.

모든 의견을 환영합니다.

그냥 내 질문의 한계를 정의하고 쓸모없는 토론을 피하십시오 : 변수가 다른 서브 루틴 호출에 의해 수정 될 수 있다는 것을 알고 있습니다. 주어진 프로 시저 안에서 직접 수정을 확인할 수있는 도구가 있으면 수동으로 처리 할 수 ​​있습니다.

+2

필자는 그러한 도구에 대해서는 잘 알지 못하지만 각각에 대해 의도 (intent (in))를 내려 놓고 컴파일러가 불평하는 곳을 볼 수 있습니까? 그렇습니다, 절대적으로 해킹 할 필요는 없지만 빠른 해킹이 필요한 경우에는 ... – francescalus

+1

다른 소스 파일에있는 경우 많은 컴파일러가 catch하지 않을 수도 있습니다. –

+0

F77의 변수 정의 컨텍스트 수는 최신 코드와 비교할 때 작습니다. 그렇다면 모든 코드에서 모든 정의 가능성에 관심이 있습니까, 아니면 단지 LHS 할당인지 F77인지 만 신경 쓰시겠습니까? – francescalus

답변

1

편의상 다음은 Ian의 VariableDefinitionContext 패키지를 컴파일하기위한 스크립트입니다. 그것은 (... gfortran-6.1 ifort-14이 부족 구문 지원으로 컴파일 할 수 없었다) -standard-semantics와 ifort - 16.0 성공적으로

#!/usr/bin/env python 
from __future__ import print_function 
import os 

with open("compile-order.txt", "r") as f: 
    tmp = f.read() 
allsrc = tmp.split() 

#cmd = "ifort -standard-semantics -warn -check all" 
cmd = "ifort -standard-semantics" 

obj = "" 
for src in allsrc: 
    print("compiling", src) 
    os.system((cmd + " -c %s") % (src)) 
    obj += src[ :-4 ]+ ".o " 
os.system((cmd + " %s") % (obj)) 
# Usage: ./a.out test.f90 

를 컴파일 ...하지만 다음과 같은 명령이 밝혀졌다 같은 일을 할 수 있어요 !! (@IanH 덕분에)

$ ifort -standard-semantics @compile-order.txt 

FWIW, 여기에 인쇄 (잠재적으로) 수정 변수에 대한 또 다른 파이썬 스크립트입니다. 이 스크립트는 gfortran 덤프 파일에서 다양한 기호를 검색합니다. Ian의 패키지와는 달리 Fortran 구문의 최소 집합 만 고려됩니다 (직접 할당과 기본 읽기/쓰기 문 등).

이러한 종류의 스크립트를 사용하는 잠재적 인 방법은 잠재적으로 수정 된 COMMON 변수를 찾는 것입니다. 이전에, 나는 일반적인 블록의 톤과 기존 포트란 프로그램을 수정하는 힘든 경험을했다, 그래서

#!/usr/bin/env python 

from __future__ import print_function 
import os, sys 

def pushuniq(coll, item): 
    if not (item in coll): coll.append(item) 

def getvarname(s, proc): 
    try: 
     return s.split(proc + ":")[ 1 ].split("(")[ 0 ].split("%")[ 0 ] 
    except: # ad-hoc! 
     return s.split("(")[ 0 ].split("%")[ 0 ] 

#------------------------------------------------------------------------ 
def varcheck(filename, Qwritedump=False): 
    """ 
    checks and prints potentially modified variables. 
    Usage: varcheck.py <filenames> 
    Set Qwritedump=True to write dump files. 
    """ 
    #......................................................... 
    # Generate gfortran dump file 

    cmd = "gfortran -fdump-parse-tree -c %s"   # gfort >=4.7 
    # cmd = "gfortran -fdump-fortran-original -c %s" # gfort >=5 

    with os.popen(cmd % (filename)) as p: 
     lines = p.readlines() 

    base = '.'.join(filename.split('.')[:-1]) 
    os.system("rm -f %s.{o,mod}" % (base)) # remove .o and .mod 

    if Qwritedump: 
     with open("%s.dump" % (filename), "w") as f: 
      f.write(''.join(lines)) 
    #/ 

    #......................................................... 
    # List of variables 

    varlist = {} # (potentially) modified variables 
    arglist = {} # dummy arguments 
    comlist = {} # common variables 
    modlist = {} # module variables 
    reslist = {} # result variables 
    sublist = {} # child subroutines 
    namlist = {} # namelists 

    #......................................................... 
    # Scan the dump file 

    Qread = False 
    Qgetarg = False 

    for line in lines: 

     word = line.split() 
     if len(word) == 0 : continue    # skip blank lines 
     if word[ 0 ].isdigit() : word = word[ 1: ] # remove line numbers 

     key = word[ 0 ] 

     if key == "Namespace:" : continue 

     if key == "procedure": 
      proc = word[ -1 ] 

      varlist[ proc ] = [] 
      arglist[ proc ] = [] 
      comlist[ proc ] = [] 
      modlist[ proc ] = [] 
      reslist[ proc ] = [] 
      namlist[ proc ] = [] 
      sublist[ proc ] = [] 
      continue 

     if key == "common:": continue 
     if key == "symtree:": sym = word[ 1 ].strip("'").lower() 

     # result variable 
     if (sym == proc) and (key == "result:"): 
      reslist[ proc ].append(word[ 1 ]) 

     # dummy arguments 
     if "DUMMY" in line: 
      arglist[ proc ].append(sym) 

     # common variables 
     if "IN-COMMON" in line: 
      comlist[ proc ].append(sym) 

     # module variables 
     if ("VARIABLE" in line) and ("USE-ASSOC" in line): 
      modlist[ proc ].append(sym) 

     # child subroutines 
     if key == "CALL": 
      pushuniq(sublist[ proc ], word[ 1 ]) 

     # namelists 
     if (key == "READ") and ("NML=" in line): 
      namlist[ proc ].append(word[ -1 ].split("NML=")[ -1 ]) 

     # iostat 
     if "IOSTAT=" in line: 
      tmp = line.split("IOSTAT=")[ 1 ].split()[ 0 ] 
      sym = getvarname(tmp, proc) 
      pushuniq(varlist[ proc ], (sym, "iostat")) 
     #/ 

     def addmemvar(op): 
      for v in word[ 1: ]: 
       if proc in v: 
        sym = getvarname(v, proc) 
        pushuniq(varlist[ proc ], (sym, op)) 

     # allocation 
     if key == "ALLOCATE" : addmemvar("alloc") 
     if key == "DEALLOCATE" : addmemvar("dealloc") 
     if "move_alloc" in line : addmemvar("move_alloc") 

     # search for modified variables 
     if key == "READ" : Qread = True 
     if key == "DT_END" : Qread = False 

     if (key == "ASSIGN") or \ 
      (Qread and (key == "TRANSFER")) or \ 
      (key == "WRITE" and (proc in word[ 1 ])): 

      if key == "ASSIGN" : code = "assign" 
      if key == "WRITE" : code = "write" 
      if key == "TRANSFER" : code = "read" 

      sym = getvarname(word[ 1 ], proc) 
      pushuniq(varlist[ proc ], (sym, code)) 
     #/ 
    #/ 

    all_lists = { "var": varlist, "arg": arglist, "com": comlist, 
        "mod": modlist, "res": reslist, "sub": sublist, 
        "nam": namlist } 

    #......................................................... 
    # Print results 

    for proc in varlist.keys(): 
     print("-" * 60) 
     print(proc + ":") 

     for tag in [ "arg", "com", "mod", "res" ]: 

      if tag == "arg": 
       print(" " + tag + ":", arglist[ proc ]) 
      else: 
       print(" " + tag + ":") 

      for (sym, code) in varlist[ proc ]: 
       if sym in all_lists[ tag ][ proc ]: 
        print("  %-10s (%s)" % (sym, code)) 
      #/ 
     #/ 

     print(" misc:") 
     for (sym, code) in varlist[ proc ]: 
      if ":" in sym: 
       print("  %-10s (%s)" % (sym, code)) 
     #/ 

     print(" call:", sublist[ proc ]) 

     if len(namlist[ proc ]) > 0: 
      print(" namelist:", namlist[ proc ]) 
    #/ 

    return all_lists 
#/ 

#------------------------------------------------------------------------ 
if __name__ == "__main__": 

    if len(sys.argv) == 1: 
     sys.exit("Usage: varcheck.py <filenames>") 
    else: 
     filenames = sys.argv[ 1: ] 

    for filename in filenames: 
     varcheck(filename) 
#/ 

예 1 ... 이러한 상황에 유용 할 수 있습니다 LAPACK이 zheev

$ ./varcheck.py zheev.f 
------------------------------------------------------------ 
zheev: 
    arg: ['jobz', 'uplo', 'n', 'a', 'lda', 'w', 'work', 'lwork', 'rwork', 'info'] 
     info  (assign) 
     work  (assign) 
     w   (assign) 
     a   (assign) 
    com: 
    mod: 
    res: 
    call: ['xerbla', 'zlascl', 'zhetrd', 'dsterf', 'zungtr', 'zsteqr', 'dscal'] 

예 2 : 간단한 테스트 프로그램

!-------------------------------------------------------- 
module myvar 
    character(50) :: str 
    type mytype 
     integer :: n 
    endtype 
    type(mytype) :: obj 
    integer :: foo 
end 

!-------------------------------------------------------- 
subroutine mysub(a, b, c, ios, n, p, q, r) 
    use myvar 
    dimension b(10) 
    common /com1/ dat(50), x, y, z, wtf(1000) 
    common /com2/ dat2(50) 
    integer inp, out 
    namelist /list/ str 
    namelist /list2/ p, q 
    inp = 10 ; out = 20 

    open(inp, file="test.dat", status="old", iostat=ios10) 
    read(inp, *, iostat=ios) a, (b(i), i=3,5) 
    write(out, *) "hello" 
    read(inp, *) c 
    read(inp, list) 
    close(inp, iostat=ios30) 

    write(str, "(f8.3)") a + c 

    do i = 1, n 
     dat(i) = b(i) 
    enddo 
    x = p + q 
    y = x * 2 
100 c = dat(1) + x + y 
end 

!-------------------------------------------------------- 
subroutine mysub2(& 
     a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, & 
     b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, & 
     c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) 
    a3 = 3.0 
    b5 = 5.0 
end 

!-------------------------------------------------------- 
function myfunc(x, m) 
    common /com2/ dat2(50) 
    common /com3/ dat3(50) 
100 myfunc = x + dat2(m) 
200 m = 5 
    where(dat2 < 1.0) dat2 = 500.0 
end 

!-------------------------------------------------------- 
function myfunc2() result(res) 
    use myvar 
    implicit none 
    integer :: res 
    obj % n = 500 
    res = obj % n 
    call sub2(res) 
end 

!-------------------------------------------------------- 
subroutine myalloc(a, ier) 
    implicit none 
    integer, allocatable :: a(:), b(:) 
    integer ier 
    allocate(a(10), b(20), source=0, stat=ier) 
end 

!-------------------------------------------------------- 
subroutine mydealloc(a, b, ier) 
    implicit none 
    integer, allocatable :: a(:), b(:) 
    integer ier 
    deallocate(a, b, stat=ier) 
end 

!-------------------------------------------------------- 
subroutine mymovealloc(a, b) 
    implicit none 
    integer, allocatable :: a(:), b(:) 
    call move_alloc(a, b) 
end 

!-------------------------------------------------------- 
program main 
    use myvar 
    implicit none 
    integer a, dat 
    common /com/ dat 

    call mymain_int 
    print *, a, dat, foo 
contains 
    subroutine mymain_int 
     integer b 
     a = 1 
     b = 2 
     dat = 100 
     foo = 200 
    end subroutine 
end program 

!-------------------------------------------------------- 
module mymod 
    use myvar 
    implicit none 
    integer bar 
contains 
    subroutine mymod_sub 
     use myvar 
     integer a, dat 
     common /com/ dat 

     call mymod_sub_int 
     bar = 300 
     print *, a, dat, foo, bar 
    contains 
     subroutine mymod_sub_int 
      integer b 
      a = 1 
      b = 2 
      dat = 100 
      foo = 200 
     end subroutine 
    end subroutine 
end module 

결과 :

------------------------------------------------------------ 
mysub: 
    arg: ['a', 'b', 'c', 'ios', 'n', 'p', 'q', 'r'] 
     ios   (iostat) 
     a   (read) 
     b   (read) 
     c   (read) 
     c   (assign) 
    com: 
     dat   (assign) 
     x   (assign) 
     y   (assign) 
    mod: 
     str   (write) 
    res: 
    call: [] 
    namelist: ['list'] 
------------------------------------------------------------ 
mysub2: 
    arg: ['a1', 'a10', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'b1', 'b10', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'c1', 'c10', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9'] 
     a3   (assign) 
     b5   (assign) 
    com: 
    mod: 
    res: 
    call: [] 
------------------------------------------------------------ 
myfunc: 
    arg: ['m', 'x'] 
     m   (assign) 
    com: 
     dat2  (assign) 
    mod: 
    res: 
     myfunc  (assign) 
    call: [] 
------------------------------------------------------------ 
myfunc2: 
    arg: [] 
    com: 
    mod: 
     obj   (assign) 
    res: 
     res   (assign) 
    call: ['sub2'] 
------------------------------------------------------------ 
myalloc: 
    arg: ['a', 'ier'] 
     ier   (alloc) 
     a   (alloc) 
    com: 
    mod: 
    res: 
    call: [] 
------------------------------------------------------------ 
mydealloc: 
    arg: ['a', 'b', 'ier'] 
     ier   (dealloc) 
     a   (dealloc) 
     b   (dealloc) 
    com: 
    mod: 
    res: 
    call: [] 
------------------------------------------------------------ 
mymovealloc: 
    arg: ['a', 'b'] 
     a   (move_alloc) 
     b   (move_alloc) 
    com: 
    mod: 
    res: 
    call: ['_gfortran_move_alloc'] 
------------------------------------------------------------ 
main: 
    arg: [] 
    com: 
    mod: 
    res: 
    misc: 
    call: ['mymain_int'] 
------------------------------------------------------------ 
mymain_int: 
    arg: [] 
    com: 
    mod: 
    res: 
    misc: 
     main:a  (assign) 
     main:dat (assign) 
     main:foo (assign) 
    call: [] 
------------------------------------------------------------ 
mymod_sub: 
    arg: [] 
    com: 
    mod: 
    res: 
    misc: 
     mymod:bar (assign) 
    call: ['mymod_sub_int'] 
------------------------------------------------------------ 
mymod_sub_int: 
    arg: [] 
    com: 
    mod: 
    res: 
    misc: 
     mymod_sub:a (assign) 
     mymod_sub:dat (assign) 
     mymod_sub:foo (assign) 
    call: [] 
+0

파이썬 스크립트는 훌륭한 스크립트입니다. 나는 그것이 내가 요구하고 있었던 것에 따라 대답을 벌써 받아 들였다. 난 그냥 몇 가지 테스트 프로그램에서 그것을 시도하고 작동합니다. 당신은 실제로 공통 블록 변수, 호출 함수 목록처럼 기대했던 것보다 더 가치있는 도구를 제공합니다. 나는 그것을 실제로 사용하여 피드백을 줄 것이다. 나는 오늘 더 많은 시험을하고 질문으로 돌아올 것입니다. – innoSPG

+1

실제로 문제는 아니지만, 실제로이 종류의 도구를 찾고있었습니다. (이전에 큰 패키지로 인해 크게 고생했기 때문입니다.) 이 커뮤니티 위키를 만들었으므로 필요에 따라 아무나 추가 할 수 있기를 바랍니다 (예 : 버그 !!!) – roygvib

+0

마음에 들지 않으면 글로벌 변수를 쉽게 설명 할 수 있습니까? 지금은 전역 변수에 접근 할 때 프로그램이 충돌합니다. – innoSPG

관련 문제