SPAG – Re-engineering Fortran Source Code

SPAG, the plusFORT restructuring tool, can unscramble spaghetti Fortran 66 or Fortran 77 code, and convert it to modern structured Fortran 95. It also converts back and forth between standard Fortran 77, and code with Fortran 95 extensions such as DO WHILE, ENDDO, CYCLE, EXIT and SELECT CASE.

SPAG does not change the meaning of a program, or even the order in which statements are executed; it does change the way the program logic is written down, making it much easier to understand and maintain. Blocks of code are reordered so that logically related sections are physically close, and jumps in control flow are minimised. SPAG may also replicate small code fragments where this improves the re-structured code. SPAG computes complexity metrics before and after restructuring.


Re-Structuring and Re-formatting

SPAG contains a powerful code beautifier, with dozens of options controlling spacing, case, labels, indentation, use of CONTINUE etc. You can use SPAG to switch back and forth between the F77 and F95 source forms. But SPAG goes much further:

  • SPAG identifies, and optionally removes dead code (statements which could never be executed) and clutter (variables or PARAMETERs which are declared but never used).
  • SPAG can rewrite your declarations from scratch using either Fortran 77 or Fortran 95 notation.
  • SPAG provides a simple and safe method for systematically changing the names of symbols within a program.
  • SPAG allows you to specify how upper and lower case should be used to distinguish different types of symbol. For example, local variables may be lower case, PARAMETERs upper case, dummy arguments capitalised etc. (e.g. local , PARAM , Dummyarg, COMmonvar).
  • SPAG generates symbol table files which are used by GXCHK, and may be used by user-written applications. For example it would be a simple matter to write a program to check conformance to local variable naming conventions. A detailed description of the symbol table format is supplied.

There are over 100 configuration options which allow you to customise SPAG output to local conventions and requirements.

Switch to Explicit Typing

SPAG allows you to switch programs to explicit typing by adding declarations for implicitly defined variables. Explicit typing, which in Fortran is normally enforced using IMPLICIT NONE, allows your compiler to detect errors which might otherwise remain undetected for years.

Switch to Fortran 95 and later

SPAG allows you to migrate your code to current Fortran standards.  It can convert source form, control constructs, declaration style, relational operators, and can convert COMMON blocks to MODULEs.  SPAG can detect the appropriate and insert the INTENT value for dummy arguments.  In conjunction with GXCHK, the plusFORT static analysis tool, it can help you to migrate your legacy Fortran 66 or 77 code to modern modular code, which could have been written today.

Top


Examples

Example 1 – Before
Example 1 – After
Example 2 – Fortran 66
Example 2 – Fortran 77
Example 2 – Fortran 90

Top


Example 1 – Original Spaghetti Code

      IBON=0
      IF(KON)35,19,35
   19 IF(NSQ-56)24,22,24
   22 IF(LSQ-46)5,28,5
   24 IF(NSQ-55)29,27,29
   27 IF(LSQ-45)5,28,5
   28 IBON=2
      GO TO 5
   29 IF(LSQ-32)30,31,30
   30 IF(LSQ-39)39,31,39
   31 IBON=-5
      GO TO 5
   39 IF(LSQ-35)52,51,52
   52 IF(LSQ-36)5,51,5
   51 IBON=10
      GO TO 5
   35 IF(MARK(NMOVE))36,37,37
   36 IBON=-5
      GO TO 5
   37 IBON=5
    5 end

Top

 


Example 1 – After Processing by SPAG

      ibon = 0
      IF ( kon.NE.0 ) THEN
         IF ( mark(nmove).LT.0 ) THEN
            ibon = -5
         ELSE
            ibon = 5
         ENDIF
      ELSEIF ( nsq.NE.56 ) THEN
         IF ( nsq.NE.55 ) THEN
            IF ( lsq.EQ.32 ) THEN
               ibon = -5
            ELSEIF ( lsq.EQ.39 ) THEN
               ibon = -5
            ELSEIF ( lsq.EQ.35 ) THEN
               ibon = 10
            ELSEIF ( lsq.EQ.36 ) THEN
               ibon = 10
            ENDIF
         ELSEIF ( lsq.EQ.45 ) THEN
            ibon = 2
         ENDIF
      ELSEIF ( lsq.EQ.46 ) THEN
         ibon = 2
      ENDIF
      END

Top


Example 2 – Original Fortran 66.

This subroutine picks off digits from an integer and branches depending on their value.

      SUBROUTINE OBACT(TODO)
      INTEGER TODO,DONE,IP,BASE
      COMMON /EG1/N,L,DONE
      PARAMETER (BASE=10)
   13 IF(TODO.EQ.0) GO TO 12
      I=MOD(TODO,BASE)
      TODO=TODO/BASE
      GO TO(62,42,43,62,404,45,62,62,62),I
      GO TO 13
   42 CALL COPY
      GO TO 127
   43 CALL MOVE
      GO TO 144
  404 N=-N
   44 CALL DELETE
      GO TO 127
   45 CALL PRINT
      GO TO 144
   62 CALL BADACT(I)
      GO TO 12
  127 L=L+N
  144 DONE=DONE+1
      CALL RESYNC
      GO TO 13
   12 RETURN
      END

Top


Example 2 – Fortran 77 Version.

In addition to restructuring, SPAG has renamed some variables, removed the unused variable IP, inserted declarations, and used upper and lower case to destinguish different types of variable.

      SUBROUTINE OBACT(Todo)
      IMPLICIT NONE
C*** Start of declarations inserted by SPAG
      INTEGER act , LENgth , NCHar
C*** End of declarations inserted by SPAG
      INTEGER Todo , DONe , BASE
      COMMON /EG1   / NCHar , LENgth , DONe
      PARAMETER (BASE=10)
 100  IF ( Todo.NE.0 ) THEN
         act = MOD(Todo,BASE)
         Todo = Todo/BASE
         IF ( act.EQ.1 .OR. act.EQ.4 .OR.
     &        act.EQ.7 .OR. act.EQ.8 .OR.
     &        act.EQ.9 ) THEN
            CALL BADACT(act)
            GOTO 200
         ELSEIF ( act.EQ.2 ) THEN
            CALL COPY
            LENgth = LENgth + NCHar
         ELSEIF ( act.EQ.3 ) THEN
            CALL MOVE
         ELSEIF ( act.EQ.5 ) THEN
            NCHar = -NCHar
            CALL DELETE
            LENgth = LENgth + NCHar
         ELSEIF ( act.EQ.6 ) THEN
            CALL PRINT
         ELSE
            GOTO 100
         ENDIF
         DONe = DONe + 1
         CALL RESYNC
         GOTO 100
      ENDIF
 200  RETURN
      END

Top


Example 2 – Fortran 95.

SPAG has used DO WHILE, SELECT CASE, EXIT and CYCLE. No GOTOs or labels remain. The COMMON block has been replaced by a MODULE, and all declarations rewritten using Fortran 95 syntax.

      SUBROUTINE OBACT(Todo)
      USE C_EG1
      IMPLICIT NONE
!
!*** Start of declarations rewritten by SPAG
!
! PARAMETER definitions
!
      INTEGER , PARAMETER :: BASE = 10
!
! Dummy arguments
!
      INTEGER,INTENT(INOUT) :: Todo
!
! Local variables
!
      INTEGER :: act
!
!*** End of declarations rewritten by SPAG
!
      DO WHILE ( Todo/=0 )
         act = MOD(Todo,BASE)
         Todo = Todo/BASE
         SELECT CASE (act)
         CASE (1,4,7,8,9)
            CALL BADACT(act)
            EXIT
         CASE (2)
            CALL COPY
            LENgth = LENgth + NCHar
         CASE (3)
            CALL MOVE
         CASE (5)
            NCHar = -NCHar
            CALL DELETE
            LENgth = LENgth + NCHar
         CASE (6)
            CALL PRINT
         CASE DEFAULT
            CYCLE
         END SELECT
         DONe = DONe + 1
         CALL RESYNC
      ENDDO
      END SUBROUTINE OBACT

Top