Skip to content
Snippets Groups Projects
Select Git revision
  • afb64fce21c3e617df95159556890e32a811dd1c
  • master default protected
2 results

src-normal.py

Blame
  • user avatar
    Miguel Carvajal authored
    afb64fce
    History
    src-normal.py 5.86 KiB
    #!/usr/bin/env python
    
    # (C) 2010 Norbert Nemec
    #
    # USAGE: src-normal.py < input.f90 > output.f90
    #
    # Script to normalize Fortran source code:
    #   a) expand tabs to spaces (tab width 8 characters)
    #   b) remove trailing space
    #   c) normalize multiword keywords
    #   d) normalize capitalization of keywords and intrinsics
    #   d) replace old relational operators (.eq., .gt., etc.) by new ones (==, >, etc.)
    # The script skips comments and strings within the code
    
    import sys,re
    
    dropspace_list = [
     "BLOCK *DATA",
     "CASE *DEFAULT",     # SPLIT NOT OPTIONAL !
     "DOUBLE *PRECISION",
     "DO *WHILE",         # SPLIT NOT OPTIONAL !
     "ELSE *IF",
     "END *BLOCK *DATA",
     "END *DO",
     "END *FILE",
     "END *FORALL",
     "END *FUNCTION",
     "END *IF",
     "END *INTERFACE",
     "END *MODULE",
     "END *PROGRAM",
     "END *SELECT",
     "END *SUBROUTINE",
     "END *TYPE",
     "END *WHERE",
     "GO *TO",
     "IN *OUT",
     "MODULE *PROCEDURE", # SPLIT NOT OPTIONAL !
     "SELECT *CASE",
    ]
    
    splitword_list = [
     "BLOCK DATA",
     "CASE DEFAULT", # SPLIT NOT OPTIONAL
     "DOUBLE PRECISION",
     "DO WHILE", # SPLIT NOT OPTIONAL
    # "ELSEIF", # leave as one word
     "END BLOCK DATA",
    # "ENDDO",  # leave as one word
     "END FILE",
     "END FORALL",
     "END FUNCTION",
    # "ENDIF",  # leave as one word
     "END INTERFACE",
     "END MODULE",
     "END PROGRAM",
     "END SELECT",
     "END SUBROUTINE",
     "END TYPE",
     "END WHERE",
    # "GOTO",   # leave as one word
    # "INOUT",  # leave as one word
     "MODULE PROCEDURE", # SPLIT NOT OPTIONAL
     "SELECT CASE",
    ]
    
    
    dropspace_re = re.compile(r"\b("+"|".join(dropspace_list)+r")\b",re.I)
    
    def dropspace_fn(s):
        return s.group(0).replace(" ","")
    
    splitword_dict = dict( (a.replace(" ","").lower(),a) for a in splitword_list )
    splitword_re = re.compile(r"\b("+"|".join(splitword_list).replace(" ","")+r")\b",re.I)
    
    def splitword_fn(s):
        return splitword_dict[s.group(0).lower()]
    
    
    uppercase_keywords = r"""
    MODULE SUBROUTINE PROGRAM FUNCTION INTERFACE
    ENDMODULE ENDSUBROUTINE ENDPROGRAM ENDFUNCTION ENDINTERFACE
    BLOCKDATA DOUBLEPRECISION
    MODULEPROCEDURE
    TYPE ENDTYPE
    CONTAINS
    USE ONLY
    ALLOCATABLE DIMENSION INTENT EXTERNAL INTRINSIC OPTIONAL PARAMETER POINTER
    COMMON
    FORMAT
    IMPLICIT NONE
    PRIVATE PUBLIC
    CHARACTER COMPLEX INTEGER LOGICAL
    ENTRY EQUIVALENCE INCLUDE NAMELIST SAVE SEQUENCE TARGET
    ELEMENTAL PURE RECURSIVE RESULT
    
    SELECTCASE CASE CASEDEFAULT ENDSELECT
    IF THEN ELSEIF ELSE ENDIF
    WHERE ELSEWHERE ENDWHERE
    FORALL ENDFORALL
    DO DOWHILE ENDDO
    
    ALLOCATE ASSIGN BACKSPACE CALL CLOSE CONTINUE CYCLE DEALLOCATE ENDFILE
    EXIT FORMAT GOTO INQUIRE NULLIFY OPEN PAUSE PRINT READ RETURN REWIND STOP WRITE
    
    """.split()
    
    lowercase_keywords = r"""
    in inout out
    """.split()
    
    intrinsics = r"""
    abort abs achar acos acosd acosh adjustl adjustr aimag aint all allocated and anint any asin
    asind asinh associated atan atan2 atan2d atand atanh
    baddress bit_size btest
    ceiling char cmplx conjg cos cosd cosh count cshift
    date date_and_time dble dcmplx dfloat digits dim dnum dot_product dprod dreal
    eoshift epsilon exit exp exponent
    floor flush fnum fraction free fset fstream
    getarg getenv gran
    hfix huge
    iachar iaddr iand iargc ibclr ibits ibset ichar idate idim ieor igetarg ijint imag index int int1
    int2 int4 int8 inum iomsg ior iqint irand iranp ishft ishftc isign ixor izext
    jnum jzext
    kind kzext
    lbound len len_trim lge lgt lle llt loc log log10 lshft lshift
    malloc matmul max maxexponent maxloc maxval mclock merge min minexponent minloc minval mod modulo mvbits
    nearest nint not
    or
    pack precision present product
    qext qfloat qnum qprod
    radix ran rand random_number random_seed range repeat reshape rnum rrspacing rshft rshift
    scale scan secnds selected_int_kind selected_real_kind set_exponent shape sign sin sind sinh size
    sizeof spacing spread sqrt srand sum system system_clock
    tan tand tanh time tiny transfer transpose trim
    ubound unpack
    verify xor zext
    """.split()
    
    ignore_for_the_moment = r"""
    real REAL isnan
    """
    
    special_keywords = r"""
    .and. .or. .not. .true. .false. .eqv. .neqv.
    .eq. .ge. .gt. .le. .lt. .ne.
    """.replace(".","\\.").split()
    
    def uppercase_fn(s):
        return s.group(0).upper()
    
    def lowercase_fn(s):
        return s.group(0).lower()
    
    def special_fn(s):
        res = s.group(0).lower()
        res = {
        '.eq.': '==',
        '.ge.': '>=',
        '.gt.': '>',
        '.le.': '<=',
        '.lt.': '<',
        '.ne.': '/=',
        }.get(res,res)
        return res
    
    uppercase_re = re.compile(r"\b("+"|".join(uppercase_keywords)+r")\b",re.I)
    lowercase_re = re.compile(r"\b("+"|".join(lowercase_keywords+intrinsics)+r")\b",re.I)
    special_re = re.compile(r"("+"|".join(special_keywords)+r")",re.I)
    
    def correctcase(line):
        line = dropspace_re.sub(dropspace_fn,line)
        line = uppercase_re.sub(uppercase_fn,line)
        line = lowercase_re.sub(lowercase_fn,line)
        line = special_re.sub(special_fn,line)
        line = splitword_re.sub(splitword_fn,line)
        return line
    
    ##############
    
    quote = " "
    QUOTES = "'\""
    
    for lin in sys.stdin:
        lin = lin.rstrip().expandtabs()
        pos = 0
        lout = ""
        if lin[:1] == "#":
            lout=lin
            pos=len(lin)
        while pos < len(lin):
            if quote in QUOTES:
                npos = lin.find(quote,pos)
                if npos >= 0:
                    assert lin[npos] == quote
                    lout += lin[pos:npos+1]
                    pos = npos+1
                    quote = " "
                elif lin[-1] == "&":
                    lout += lin[pos:]
                    break
                else:
                    raise "unterminated string in line ["+lin+"]"
    
            cpos = lin.find("!",pos) % (len(lin)+1)
            qpos = lin.find("'",pos) % (len(lin)+1)
            dpos = lin.find('"',pos) % (len(lin)+1)
            npos = min(cpos,qpos,dpos)
            lout += correctcase(lin[pos:npos])
            pos = npos
            if pos == len(lin):
                break
            elif lin[pos] == "!":
                lout += lin[pos:]
                break
            elif lin[pos] in QUOTES:
                quote = lin[pos]
                lout += quote
                pos += 1
                continue
            else:
                raise "Strange internal error"
    
        sys.stdout.write(lout+"\n")