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.
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 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.
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.
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
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
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
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
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