1 ! ftp://ftp.numerical.rl.ac.uk/pub/MandR/convert.f90
3 ! Copyright CERN, Geneva 1991, 1997 - Copyright and any other
4 ! appropriate legal protection of these computer programs
5 ! and associated documentation reserved in all countries
7 ! Author: Michael Metcalf (MichaelMetcalf@compuserve.com)
9 ! Requires the option -qcharlen=14400 with IBM's xlf.
11 ! Version 1.5. Differs from previous versions in that:
13 ! Code modified to be Fortran 95 and ELF
14 ! compatible (no functional changes).
16 !***********************************************************************
19 ! A program to convert FORTRAN 77 source form to Fortran 90 source *
20 ! form. It also formats the code by indenting the bodies of DO-loops *
21 ! and IF-blocks by ISHIFT columns. Statement keywords are *
22 ! followed if necessary by a blank, and blanks within tokens are *
23 ! are suppressed; this handling of blanks is optional. *
24 ! If a CONTINUE statement terminates a single DO loop, it is *
25 ! replaced by END DO. *
26 ! Procedure END statements have the procedure name added, if *
27 ! blanks are handled. *
28 ! Statements like INTEGER*2 are converted to INTEGER(2), if blanks *
29 ! are handled. Depending on the target processor, a further global *
30 ! edit might be required (e.g. where 2 bytes correspond to KIND=1). *
31 ! Typed functions and assumed-length character specifications are *
32 ! treated similarly. The length specification *4 is removed for all *
33 ! data types except CHARACTER, as is *8 for COMPLEX. This *
34 ! treatment of non-standard type declarations includes any *
35 ! non-standard IMPLICIT statements. *
36 ! Optionally, interface blocks only may be produced; this requires *
37 ! blanks processing to be requested. The interface blocks are *
38 ! compatible with both the old and new source forms. *
40 ! Usage: the program reads one data record in free format from the *
41 ! default input unit. This contains: *
45 ! maximum indentation level *
46 ! whether significant blanks should be handled *
47 ! whether interface blocks only are required *
49 ! The default values in the absence of this record are: *
51 ! To do nothing but change the source form of a file prog.f type *
55 ! For more extensive processing type, say, *
57 ! and for interface blocks only type *
59 ! The input is read from prog.f, the output is written to prog.f90; *
60 ! there should be no tabs in the input. *
62 ! Restrictions: The program does not indent FORMAT statements or *
63 ! any statement containing a character string with an *
64 ! embedded multiple blank. *
65 ! The order of comment lines and Fortran statements *
66 ! is slightly modified if there are sequences of *
67 ! more than KKLIM (=200) comment lines. *
68 ! If there are syntax errors, continued lines do not *
69 ! have a trailing &. *
70 ! When producing interface blocks, a check is required*
71 ! that any dummy argument that is a procedure has a *
72 ! corresponding EXTERNAL statement. Also, since no *
73 ! COMMON blocks or PARAMETER statements are copied, *
74 ! part of an assumed-size array declaration may be *
75 ! missing. Similarly, parts of an assumed-length *
76 ! character symbolic constant might be copied and have *
77 ! to be deleted. BLOCK DATA statements are copied and *
78 ! must be deleted. These problems would normally be *
79 ! detected by a compiler and are trivially corrected. *
80 ! Within a given keyword, the case must be all upper *
81 ! or all lower, and lower case programs require *
82 ! blank handling for correct indenting. *
84 !***********************************************************************
88 !***********************************************************************
89 ! Define maximum level of DO-loop nesting, and maximum length of *
90 ! a Fortran statement. LEN may be reduced for *
91 ! compilers accepting a maximum character *
92 ! length below 2640 and this will cause any excess *
93 ! continuation lines and all following lines to be copied unchanged. *
94 ! KKLIM defines the length of the comment line buffer. If this *
95 ! length is exceeded, the statement preceding the comments will *
96 ! appear after them. *
97 !***********************************************************************
100 INTEGER, PARAMETER :: NEST
= 32 , LEN
= 2640 , KKLIM
= 200, &
103 INTEGER :: KNTDO
, KNTIF
, KNTCOM
, LABEL
, LENST
, LABLNO
, NOARG
104 INTEGER, DIMENSION(NEST
) :: LABLDO
106 LOGICAL :: SYNERR
, BLNKFL
, INTFL
108 CHARACTER(LEN
=LEN
) :: STAMNT
109 CHARACTER(LEN
=KLEN
):: CBUF
110 CHARACTER(LEN
=42) :: NAME
117 INTEGER, SAVE :: ISHIFT
, MXDPTH
, NIN
, NOUT
, TIME0
118 LOGICAL, SAVE :: BLANKS
, INTBFL
125 INTEGER, SAVE :: MXDO
, MXIF
, KARD
, KNTPU
127 LOGICAL, SAVE :: SYNTAX
, OVFLW
, NONSTD
129 END MODULE STATISTICS
130 MODULE ALL_PROCEDURES
132 public
:: start
, program_units
, terminate
134 !***********************************************************************
135 SUBROUTINE ARGUMENT(ARGNAM
, LENARG
, STAMNT
, LENST
, NOARG
)
138 ! To store the argument names and function name, if any, for later
139 ! use in checking whether a specification statement is relevant to an
141 CHARACTER(LEN
=*), INTENT(IN OUT
), dimension(:) :: ARGNAM
142 CHARACTER(LEN
=*), INTENT(IN
) :: STAMNT
143 INTEGER, INTENT(OUT
), dimension(:) :: LENARG
144 INTEGER, INTENT(IN OUT
) :: NOARG
145 INTEGER, INTENT(IN
) :: LENST
147 integer :: ind1
, ind2
, newind
149 ! Correct length of function name
150 IF (NOARG
== 1) LENARG(1) = LEN_TRIM(ARGNAM(1))
152 ! Get any other arguments
153 IND1
= index(STAMNT(:LENST
), '(') + 1
154 IF (IND1
/= 1 .AND
. STAMNT(IND1
:IND1
) /= ')') THEN
155 NEWIND
= index(STAMNT(IND1
+1:LENST
), '(')
156 IF (NEWIND
/= 0) IND1
= NEWIND
+ 1 + IND1
157 3 IND2
= index(STAMNT(IND1
:LENST
), ',') - 1
158 IF (IND2
== -1) IND2
= index(STAMNT(IND1
:LENST
), ')') - 1
159 IND2
= IND2
+ IND1
- 1
160 IF (STAMNT(IND1
+1:IND1
+1) /= '*' ) THEN
162 ARGNAM(NOARG
) = STAMNT(IND1
:IND2
)
163 LENARG(NOARG
) = IND2
- IND1
+1
165 IF (STAMNT(IND2
+1:IND2
+1) == ')') GO
TO 4
169 4 LENARG(:NOARG
) = MIN(LENARG(:NOARG
), 6)
172 END SUBROUTINE ARGUMENT
175 ! To suppress all blanks in the statement, and then to place
176 ! a blank on each side of =, +, -, * and / (but not ** or //), a
177 ! blank after each ) and , and a blank before each (.
178 ! No changes are made within character strings or FORMAT statememts.
187 CHARACTER(LEN
=LEN
) :: BUFFER
188 integer :: l1
, l2
, lchar
, napost
, lenold
190 ! Reduce length to that of significant characters
192 LENST
= LEN_TRIM(STAMNT(1:LENST
))
193 IF (.NOT
.BLANKS
) THEN
194 IF (LEN
-LENST
>= 2) STAMNT(LENST
+1:LENST
+2) = ' '
195 LENST
= MIN(LENST
+2, LEN
)
200 ! Suppress blanks (add 2 to catch
201 ! odd number of apostrophes on a line in REFORM).
205 IF (STAMNT(L1
:L1
) == "'") NAPOST
= 1-NAPOST
206 IF (NAPOST
== 0 .AND
. STAMNT(L1
:L1
) == ' ') CYCLE
208 BUFFER(LCHAR
:LCHAR
) = STAMNT(L1
:L1
)
210 IF (LEN
-LCHAR
>= 2) BUFFER(LCHAR
+1:LCHAR
+2) = ' '
211 LCHAR
= MIN(LCHAR
+2, LEN
)
214 IF( LABEL
/= 0 .AND
. &
215 & LCHAR
>= 11 .AND
.(BUFFER(:7) == 'FORMAT(' .OR
. &
216 & BUFFER(:7) == 'format(') .AND
. &
217 & BUFFER(LCHAR
-2:LCHAR
-2) == ')') THEN
218 IF (LEN
-LENST
>= 2) STAMNT(LENST
+1:LENST
+2) = ' '
219 LENST
= MIN(LENST
+2, LEN
)
229 ! Check size of statement
230 IF(LENST
+3 > LEN
) THEN
232 STAMNT(:LENST
) = BUFFER(:LENST
)
237 ! Whether inside character string
238 IF (BUFFER(L2
:L2
) == "'") NAPOST
= 1-NAPOST
239 IF (NAPOST
== 1) GO
TO 3
241 ! Add blank padding according to character
242 SELECT
CASE (BUFFER(L2
:L2
))
244 STAMNT(LENST
+1:LENST
+2) = ') '
247 STAMNT(LENST
+1:LENST
+2) = ' ('
250 STAMNT(LENST
+1:LENST
+2) = ', '
253 STAMNT(LENST
+1:LENST
+3) = ' = '
256 IF (BUFFER(L2
-1:L2
-1) /= '*' .AND
. BUFFER(L2
+1:L2
+1) &
258 STAMNT(LENST
+1:LENST
+3) = ' * '
264 IF (BUFFER(L2
-1:L2
-1) /= '/' .AND
. BUFFER(L2
+1:L2
+1) &
266 STAMNT(LENST
+1:LENST
+3) = ' / '
272 IF (BUFFER(L2
-1:L2
-1) /= 'E' .AND
. &
273 BUFFER(L2
-1:L2
-1) /= 'e' .AND
. &
274 BUFFER(L2
-1:L2
-1) /= 'D' .AND
. &
275 BUFFER(L2
-1:L2
-1) /= 'd' .OR
. &
276 LLT(BUFFER(L2
+1:L2
+1), '0') .AND
. LGT(BUFFER(L2
+1:L2
+1), '9')&
278 STAMNT(LENST
+1:LENST
+3) = ' + '
284 IF (BUFFER(L2
-1:L2
-1) /= 'E' .AND
. &
285 BUFFER(L2
-1:L2
-1) /= 'e' .AND
. &
286 BUFFER(L2
-1:L2
-1) /= 'D' .AND
. &
287 BUFFER(L2
-1:L2
-1) /= 'd' .OR
. &
288 LLT(BUFFER(L2
+1:L2
+1), '0') .AND
. LGT(BUFFER(L2
+1:L2
+1), '9')&
290 STAMNT(LENST
+1:LENST
+3) = ' - '
299 3 STAMNT(LENST
+1:LENST
+1) = BUFFER(L2
:L2
)
303 ! Blank out end of statement
304 IF (LENOLD
> LENST
) STAMNT(LENST
+1:LENOLD
) = ' '
305 IF (LENST
< LEN
.AND
. MOD(LENST
, 66) /= 0) &
306 STAMNT(LENST
+1: LENST
+66-MOD(LENST
, 66)) = ' '
310 SUBROUTINE IDENTIFY (IRET
)
312 !***********************************************************************
313 ! To identify statement as beginning or end of DO-loop or *
314 ! IF-block, or as probable FORMAT. *
315 ! Attempt to scan as few of the input characters as possible. *
316 !***********************************************************************
322 CHARACTER(LEN
=5), PARAMETER :: ENDIF='ENDIF' , THEN='NEHT)', &
324 CHARACTER(LEN
=3), PARAMETER :: BIF
='IF('
325 CHARACTER(LEN
=2), PARAMETER :: DO='DO'
326 CHARACTER(LEN
=7), PARAMETER :: FORMAT='FORMAT('
327 CHARACTER(LEN
=4), PARAMETER :: ELSE='ELSE'
328 CHARACTER(LEN
=5) :: INTFIL
329 INTEGER, INTENT(OUT
) :: IRET
331 integer :: l1
, l2
, l3
, l4
, l5
, l6
, l7
, l8
, l9
, l10
, l11
, l12
, &
332 k1
, k2
, k3
, k5
, k6
, k7
, k8
, lparen
, kntch
, napos
336 ! Check whether end of DO-loop
338 IF (LABEL
== LABLDO(KNTDO
)) THEN
344 ! Check whether any of remaining possibilities
346 IF (STAMNT(L7
:L7
) == ' ') CYCLE
347 IF (STAMNT(L7
:L7
) == 'E') THEN
348 DO L11
= L7
+1 , LENST
349 IF (STAMNT(L11
:L11
) == ' ') CYCLE
350 IF (STAMNT(L11
:L11
) == ENDIF(2:2)) GO
TO 6
351 IF (STAMNT(L11
:L11
) == ELSE(2:2)) GO
TO 3
355 IF (STAMNT(L7
:L7
) == BIF(:1)) GO
TO 9
356 IF (STAMNT(L7
:L7
) == DO(:1)) GO
TO 15
357 IF (STAMNT(L7
:L7
) == FORMAT(:1)) GO
TO 31
362 ! Check whether ELSE or ELSEIF
364 DO L12
= L11
+1 , LENST
365 IF (STAMNT(L12
:L12
) == ' ') CYCLE
366 IF (STAMNT(L12
:L12
) /= ELSE(K8
:K8
)) GO
TO 99
371 5 IF (L12
>= LENST
) THEN
375 IF (STAMNT(L12
+1:LENST
) == ' ') THEN
384 ! Check whether end of IF-block
386 DO L1
= L11
+1 , LENST
387 IF (STAMNT(L1
:L1
) == ' ') CYCLE
388 IF (STAMNT(L1
:L1
) /= ENDIF(K1
:K1
)) GO
TO 99
392 IF (L1
>= LENST
) THEN
396 IF (STAMNT(L1
+1:LENST
) == ' ') IRET
= 4
399 ! Check whether beginning of IF-block
402 10 DO L2
= L7
+1 , LENST
403 IF (STAMNT(L2
:L2
) == ' ') CYCLE
404 IF (STAMNT(L2
:L2
) /= BIF(K2
:K2
)) THEN
408 IF (K2
== 3) GO
TO 12
414 ! Backward search for )THEN at end of IF statement (to save
415 ! scanning the condition).
417 DO L3
= LENST
, L2
+1 , -1
418 IF (STAMNT(L3
:L3
) == ' ') CYCLE
419 IF (STAMNT(L3
:L3
) /= THEN(K3
:K3
) .AND
. &
420 STAMNT(L3
:L3
) /= THENLC(K3
:K3
)) THEN
424 IF (K3
== 5) GO
TO 99
430 ! Check whether beginning of DO-loop
431 15 DO L4
= L7
+1 , LENST
432 IF (STAMNT(L4
:L4
) == ' ') CYCLE
433 IF (STAMNT(L4
:L4
) == DO(2:2)) GO
TO 17
438 ! Have DO - check label
442 IF (STAMNT(L5
:L5
) == ' ') CYCLE
443 IF (LLT(STAMNT(L5
:L5
) , '0') .OR
. LGT(STAMNT(L5
:L5
) , '9')) &
447 INTFIL(K5
:K5
) = STAMNT(L5
:L5
)
449 IF (K5
== 0) GO
TO 99
450 20 READ (INTFIL
, '(BN , I5)') LABLNO
451 IF (LABLNO
== 0) GO
TO 99
453 ! Have label - check comma
455 IF (STAMNT(L8
:L8
) == ' ') CYCLE
456 IF (STAMNT(L8
:L8
) == ',') EXIT
462 ! Have a DO and label with no comma.
463 ! Check for variable whose first of maximum of six
464 ! characters is alphabetic, followed by an equals sign,
465 ! followed by a character string containing a comma which is
466 ! not enclosed in parentheses.
469 IF (STAMNT(L9
:L9
) == ' ') CYCLE
471 IF ((LLT(STAMNT(L9
:L9
), 'A') .OR
. LGT(STAMNT(L9
:L9
), 'Z')) &
472 .AND
.(LLT(STAMNT(L9
:L9
), 'a') .OR
. LGT(STAMNT(L9
:L9
), 'z')))&
475 ELSE IF (LGE(STAMNT(L9
:L9
) , 'A') .AND
. LLE(STAMNT(L9
:L9
),'Z')&
476 .OR
. LGE(STAMNT(L9
:L9
) , 'a') .AND
. LLE(STAMNT(L9
:L9
) ,'z')&
477 .OR
. LGE(STAMNT(L9
:L9
) , '0') .AND
. LLE(STAMNT(L9
:L9
) , '9')) &
480 IF (K6
== 6) GO
TO 26
482 IF (K6
== 0) GO
TO 99
488 ! Expect an equals sign
490 26 DO L10
= L9
+1 , LENST
491 IF (STAMNT(L10
:L10
) == ' ') CYCLE
492 IF (STAMNT(L10
:L10
) == '=') GO
TO 28
497 ! Search for bare comma
501 DO L6
= L10
+1 , LENST
502 IF (STAMNT(L6
:L6
) == ' ') CYCLE
503 IF (STAMNT(L6
:L6
) == "'") NAPOS
= 1 - NAPOS
504 IF (NAPOS
== 1) CYCLE
505 IF (STAMNT(L6
:L6
) == ',') THEN
507 IF (LPAREN
== 0) GO
TO 30
512 ELSE IF (STAMNT(L6
:L6
) == '(') THEN
514 ELSE IF (STAMNT(L6
:L6
) == ')') THEN
522 ! Insert blank after label
523 IF (.NOT
.BLANKS
.OR
. LENST
>= LEN
) GO
TO 99
524 DO L10
= LENST
, L5
, -1
525 STAMNT(L10
+1:L10
+1) = STAMNT(L10
:L10
)
531 ! Identify FORMAT statement
532 31 IF (LABEL
== 0) GO
TO 99
534 DO L11
= L7
+1 , LENST
535 IF (STAMNT(L11
:L11
) == ' ') CYCLE
536 IF (STAMNT(L11
:L11
) /= FORMAT(K7
:K7
)) GO
TO 99
537 IF (K7
== 7) GO
TO 33
544 END SUBROUTINE IDENTIFY
545 SUBROUTINE KEYWORD(ASSIGN, SKIP
)
547 ! To check whether those initial keywords of the statement which
548 ! require it are followed by a blank, to add one if necessary, and
549 ! to suppress any embedded blanks.
556 LOGICAL, INTENT(OUT
) :: ASSIGN, SKIP
558 INTEGER, PARAMETER :: NKEY
= 42, MAXLEN
= 15
559 CHARACTER(LEN
=MAXLEN
) :: BEGIN
560 CHARACTER(LEN
=LEN
) :: BUFFER
561 CHARACTER(LEN
=3) :: THREE
562 CHARACTER(LEN
=32) :: NAMEOF
563 CHARACTER(LEN
=6), SAVE :: ARGNAM(445)
565 INTEGER, SAVE :: LENARG(445)
567 CHARACTER(LEN
=MAXLEN
), PARAMETER, dimension(nkey
) :: KEYS
= (/ &
568 'ASSIGN ', 'BACKSPACE ', 'BLOCKDATA ', &
569 'CALL ', 'CHARACTER ', 'CLOSE ', &
570 'COMMON ', 'COMPLEX ', 'CONTINUE ', &
571 'DATA ', 'DIMENSION ', 'DOUBLEPRECISION', &
572 'DO ', 'ELSEIF ', 'ELSE ', &
573 'ENDFILE ', 'ENDIF ', 'ENTRY ', &
574 'EXTERNAL ', 'EQUIVALENCE ', 'FORMAT ', &
575 'FUNCTION ', 'GOTO ', 'IF ', &
576 'IMPLICIT ', 'INQUIRE ', 'INTEGER ', &
577 'INTRINSIC ', 'LOGICAL ', 'OPEN ', &
578 'PARAMETER ', 'PAUSE ', 'PRINT ', &
579 'PROGRAM ', 'READ ', 'REAL ', &
580 'RETURN ', 'REWIND ', 'SAVE ', &
581 'STOP ', 'SUBROUTINE ', 'WRITE '/)
582 INTEGER, PARAMETER, dimension(nkey
) :: LK
= &
591 LOGICAL, PARAMETER, dimension(nkey
) :: BLANK
= &
592 (/.TRUE
., .TRUE
., .TRUE
., .TRUE
., &
593 .TRUE
., .FALSE
., .TRUE
., .TRUE
., .FALSE
., .TRUE
., &
594 .TRUE
., .TRUE
., .TRUE
., .FALSE
., .FALSE
., &
595 .TRUE
., .FALSE
., .TRUE
., .TRUE
., .FALSE
., &
596 .FALSE
., .TRUE
., .TRUE
., .FALSE
., .TRUE
., .FALSE
., &
597 .TRUE
., .TRUE
., .TRUE
., .FALSE
., .TRUE
., &
598 .TRUE
., .TRUE
., .TRUE
., .TRUE
., .TRUE
., .TRUE
., &
599 .TRUE
., .TRUE
., .TRUE
., .TRUE
., .FALSE
./)
600 LOGICAL, PARAMETER, dimension(nkey
) :: FOLLOW
= &
601 (/.TRUE
., .TRUE
., .FALSE
., .TRUE
., &
602 .FALSE
., .FALSE
., .FALSE
., .FALSE
., .FALSE
., .FALSE
., &
603 .FALSE
., .FALSE
., .FALSE
., .FALSE
., .FALSE
., &
604 .TRUE
., .FALSE
., .FALSE
., .FALSE
., .FALSE
., &
605 .FALSE
., .FALSE
., .TRUE
., .FALSE
., .FALSE
., .FALSE
., &
606 .FALSE
., .FALSE
., .FALSE
., .FALSE
., .FALSE
., &
607 .TRUE
., .TRUE
., .FALSE
., .TRUE
., .FALSE
., .TRUE
., &
608 .TRUE
., .FALSE
., .TRUE
., .FALSE
., .FALSE
./)
610 CHARACTER(LEN
=MAXLEN
), PARAMETER, dimension(nkey
) :: KEYSLC
= (/ &
611 'assign ', 'backspace ', 'blockdata ', &
612 'call ', 'character ', 'close ', &
613 'common ', 'complex ', 'continue ', &
614 'data ', 'dimension ', 'doubleprecision', &
615 'do ', 'elseif ', 'else ', &
616 'endfile ', 'endif ', 'entry ', &
617 'external ', 'equivalence ', 'format ', &
618 'function ', 'goto ', 'if ', &
619 'implicit ', 'inquire ', 'integer ', &
620 'intrinsic ', 'logical ', 'open ', &
621 'parameter ', 'pause ', 'print ', &
622 'program ', 'read ', 'real ', &
623 'return ', 'rewind ', 'save ', &
624 'stop ', 'subroutine ', 'write '/)
626 integer :: l1
, l2
, l3
, l4
, l5
, l6
, l7
, l20
, lparen
, kntap
, kntch
,&
627 lc
, lcc
, l33
, next
, l8
, napos
, lsave
, name_length
629 ! Test for statement function statement or assignment statement
638 IF (STAMNT(L1
:L1
)==' ') CYCLE
639 IF (STAMNT(L1
:L1
)=='=') THEN
640 IF (KNTCH
==0) SYNERR
= .TRUE
.
641 IF (LPAREN
==0 .AND
. KNTAP
==0) THEN
647 ELSE IF (STAMNT(L1
:L1
)=='(') THEN
649 ELSE IF (STAMNT(L1
:L1
)==')') THEN
651 ELSE IF (STAMNT(L1
:L1
)=="'") THEN
655 IF (KNTCH
<=3) THREE(KNTCH
:KNTCH
) = STAMNT(L1
:L1
)
658 ! Suppress blanks in first 15 non-blank characters
662 IF (STAMNT(L2
:L2
)==' ') CYCLE
664 BEGIN(LC
:LC
) = STAMNT(L2
:L2
)
665 IF (LC
==MAXLEN
) GO
TO 3
669 ! Is this a keyword? Failure of this test is not fatal, in order to
670 ! allow for non-standard syntax extensions.
672 IF (BEGIN(:LK(L3
)) == KEYS(L3
)(:LK(L3
))) THEN
674 ELSE IF (BEGIN(:LK(L3
)) == KEYSLC(L3
)(:LK(L3
))) THEN
677 IF (STAMNT(L33
:L33
) == ' ') CYCLE
679 IF (LCC
== LK(L3
)) EXIT
681 STAMNT(:L33
) = KEYS(L3
)(:LK(L3
))
688 ! Test for embedded blanks in keyword
692 IF (STAMNT(L4
:L4
)==' ') CYCLE
694 IF (LC
==LK(L3
)) GO
TO 7
697 7 IF (L4
==LC
) GO
TO 8
698 STAMNT(:L4
) = KEYS(L3
)(:LC
)
702 ! Keyword has no blanks - is it followed by a blank if it needs one?
703 8 IF (.NOT
.BLANK(L3
)) GO
TO 99
707 IF (STAMNT(NEXT
:NEXT
)==' ') GO
TO 17
710 IF (STAMNT(NEXT
:NEXT
)==' ') GO
TO 99
712 ! Sometimes a delimiter may be present
713 IF (L3
==2.OR
.L3
==16.OR
.L3
==23.OR
.L3
==35.OR
.L3
==38) THEN
714 IF (STAMNT(NEXT
:NEXT
)=='(') GO
TO 99
716 IF (STAMNT(NEXT
:NEXT
)=='*') GO
TO 99
717 ELSE IF (L3
==7.OR
.L3
==39) THEN
718 IF (STAMNT(NEXT
:NEXT
)=='/') GO
TO 99
726 BUFFER(NEXT
:LENST
) = STAMNT(NEXT
:LENST
)
728 STAMNT(NEXT
:NEXT
) = ' '
729 STAMNT(NEXT
+1:LENST
) = BUFFER(NEXT
:LENST
-1)
733 ! Check whether, in fact, a DO-loop
734 9 IF (THREE(:2) /= 'DO' .AND
. THREE(:2) /= 'do') GO
TO 12
738 IF (STAMNT(L5
:L5
)==' ') CYCLE
739 IF (STAMNT(L5
:L5
) == "'") NAPOS
= 1 - NAPOS
740 IF (NAPOS
== 1) CYCLE
741 IF (STAMNT(L5
:L5
)==',') THEN
746 ELSE IF (STAMNT(L5
:L5
)=='(') THEN
748 ELSE IF (STAMNT(L5
:L5
)==')') THEN
754 ! Check whether, in fact, a logical IF followed by an assignment
755 12 IF (THREE
/= 'IF(' .AND
. THREE
/= 'if(') GO
TO 99
758 IF (STAMNT(L6
:L6
)==' ') CYCLE
759 IF (STAMNT(L6
:L6
)==')') THEN
761 ! Is there a second pair of first-level parentheses
762 IF (index(STAMNT(:L6
), ')')==0) GO
TO 99
765 IF (STAMNT(L7
:L7
)==' ') CYCLE
766 IF (STAMNT(L7
:L7
)==')') THEN
772 ELSE IF (STAMNT(L7
:L7
)=='(') THEN
785 ! Test for non-executable statement keyword
786 99 IF (ASSIGN) GO
TO 98
787 IF (.NOT
.INTFL
) GO
TO 97
788 SKIP
= L3
== 3.OR
.L3
== 5.OR
.L3
== 8 &
789 .OR
.L3
== 11.OR
.L3
== 12.OR
.L3
== 19.OR
.L3
== 22 &
790 .OR
.L3
== 25.OR
.L3
== 27.OR
.L3
== 29 &
791 .OR
.L3
== 34.OR
.L3
== 36.OR
.L3
== 41
795 ! Check whether this statement refers to an argument or a function
797 IF (L3
== 3 .OR
. L3
== 22 .OR
. L3
== 25 .OR
. &
798 L3
== 34 .OR
. L3
== 41) GO
TO 97
799 IF(index(STAMNT(LK(L3
)+1:LENST
), 'FUNCTION')/= .0 .OR
. &
800 index(STAMNT(LK(L3
)+1:LENST
), 'function') /= 0) GO
TO 97
802 IF(index(STAMNT(LK(L3
)+1:LENST
), ARGNAM(L20
)(:LENARG(L20
))) &
808 ! Keep procedure name for END statement
809 97 call name_of(nameof
, stamnt(lk(l3
)+2:lenst
), name_length
)
810 IF(L3
== 3.OR
.L3
== 22.OR
.L3
== 34.OR
. &
811 L3
== 41) NAME
= KEYS(L3
)(:LK(L3
))//NAMEOF(:name_length
)
813 ! Get argument names for later use in skipping unnecessary
817 ARGNAM(1) = NAME(10:15)
820 IF (L3
== 22 .OR
. L3
== 41) &
821 CALL ARGUMENT(ARGNAM
, LENARG
, STAMNT
, LENST
, NOARG
)
824 ! Deal with awkward cases
826 IF(L3
== 1.OR
.L3
== 5.OR
.L3
== 8.OR
.L3
== 12 .OR
. L3
== 13 &
828 .OR
.L3
== 24.AND
..NOT
.IFASS
.OR
.L3
== 27.OR
.L3
== 29.OR
.L3
== 36) &
829 CALL SPECIAL(L3
, NEXT
, BUFFER
, NKEY
, KEYS
, KEYSLC
, LK
, FOLLOW
)
831 ! Was, in fact, a function
832 IF (INTFL
.AND
.L3
== 22.AND
.LSAVE
/= 22) THEN
837 ! Print procedure name
838 98 IF(.NOT
.ASSIGN.AND
.(L3
== 3.OR
.L3
== 22.OR
.L3
== 34.OR
.L3
== 41))&
839 WRITE (*, '('' Starting '', A)') NAME
841 END SUBROUTINE KEYWORD
842 subroutine NAME_OF(nameof
, HEADER
, name_length
)
845 ! Pick out name of procedure
846 CHARACTER(LEN
=*), INTENT(IN
) :: HEADER
847 CHARACTER(LEN
=*), INTENT(out
):: nameof
848 integer, intent(out
) :: name_length
849 integer :: ind
, indast
853 ! Is there a left parenthesis or an asterisk?
854 IND
= index(HEADER
, '(' )
855 INDAST
= index(HEADER
, '*')
856 IF (IND
/= 0 .AND
. INDAST
/= 0) IND
= MIN(IND
, INDAST
)
857 IF (IND
<= LEN(NAMEOF
)) THEN
859 NAMEOF(2:) = HEADER(:LEN(HEADER
))
860 name_length
= min(len(header
)+1, len(nameof
))
862 NAMEOF(2:IND
) = HEADER(:IND
-1)
867 END subroutine NAME_OF
868 SUBROUTINE PROGRAM_UNITS( )
870 !***********************************************************************
871 ! The principal subroutine of CONVERT processes the *
872 ! input stream, which is assumed to contain syntactically correct *
873 ! Fortran program units. To protect itself from bad data, failure *
874 ! to pass a primitive syntax check will cause the program to copy *
875 ! the input stream to the output unit unchanged, until an END line is*
877 !***********************************************************************
886 !***********************************************************************
887 ! USER is a character which may be defined to identify lines *
888 ! in the input stream which are to be treated as *
889 ! comment lines ( + in this example). *
890 !***********************************************************************
892 CHARACTER(LEN
=1) :: CONTIN
893 CHARACTER(LEN
=3), PARAMETER :: FIN
='END', FINLC
='end'
894 CHARACTER(LEN
=66) :: FIELD
895 CHARACTER(LEN
=72) :: LINE
896 CHARACTER(LEN
=72), PARAMETER :: BLANKV
=' '
898 LOGICAL :: NEWDO
, NEWIF
, FORM
, ELSEBL
, ASSIGN
900 CHARACTER(LEN
=*), PARAMETER :: USER
= '+'
901 LOGICAL :: STAT
= .FALSE
. , SKIP
= .FALSE
.
903 integer :: l1
, l5
, l22
, kntcon
, napo
, lab
, l9
, k1
, &
906 ! Start processing program units
922 ! Set continuation line counter
925 ! Set statement length counter
928 ! Read one line into an internal file,
929 ! columns 73-80 of all lines are ignored.
930 2 READ (NIN
, '(A)' , END = 100 , ERR
= 100) LINE
933 ! Check whether a comment line and if so copy to buffer.
934 IF (LINE(:1) == 'C' .OR
. LINE(:1) == '*' .OR
. LINE(:1) == &
935 USER
.OR
. LINE
== ' ' .OR
. LINE(:1) == 'c' &
936 .OR
. LINE(:1) == '!') THEN
938 IF (LINE(:1) == 'C' .OR
. LINE(:1) == '*' &
939 .OR
. LINE(:1) == 'c') LINE(:1) = '!'
940 IF (KNTCOM
== KKLIM
) THEN
941 WRITE (NOUT
, '(A72)') (CBUF(72*L5
-71:72*L5
) , L5
= 1 , &
944 ELSE IF (SYNERR
.OR
. .NOT
.STAT
) THEN
945 WRITE (NOUT
, '(A72)') LINE
948 CBUF(72*KNTCOM
-71:72*KNTCOM
) = LINE
953 ! Some form of embedded comment?
956 IF (LINE(L22
:L22
) == '''') NAPO
= 1 - NAPO
958 IF (LINE(L22
:L22
) /= '!') CYCLE
960 IF (.NOT
. INTFL
) THEN
961 IF (KNTCOM
< KKLIM
) THEN
963 CBUF(72*KNTCOM
-71:72*KNTCOM
) = &
964 BLANKV(:L22
-1)//LINE(L22
:72)
966 WRITE (NOUT
, '(A)') BLANKV(:L22
-1)//LINE(L22
:72)
970 IF (LINE
== ' ') GO
TO 2
974 ! Line is some form of statement; re-read.
975 READ (LINE
, '(BN , I5 , A1 , A66)') LAB
, CONTIN
, FIELD
978 ! Check on syntax and copy to statement buffer
979 3 IF (CONTIN
== '0') CONTIN
= ' '
980 IF (CONTIN
/= ' ') THEN
984 ELSE IF (LENST
== 0 .OR
. LENST
+66 > LEN
.OR
. LAB
/= 0) THEN
988 WRITE (NOUT
, '(I5, 1X, A66:"&"/(5X, "&", A66: &
990 (STAMNT(66*L9
-65:66*L9
) , L9
= 1 , (LENST
+65)/66)
992 WRITE (NOUT
, '(6X, A66:"&"/(5X, "&", A66:"&" &
993 & ))') (STAMNT(66*L9
-65:66*L9
) , L9
= 1 , (LENST
+65)/66)
997 WRITE (NOUT
, 1000) LAB
, CONTIN
, FIELD
999 WRITE (NOUT
, 1006) CONTIN
, FIELD
1004 STAMNT(LENST
+1:LENST
+66) = FIELD
1008 ELSE IF (KNTCON
== 0) THEN
1009 IF (LENST
/= 0) GO
TO 4
1010 STAMNT(1:66) = FIELD
1016 IF (KNTCON
> 0) GO
TO 6
1018 ! Have a complete statement ready for processing (the last line
1019 ! read is still waiting in LINE). The statement now needs to be
1021 ! The END statement is a special case - if found it will be copied
1022 ! and the next program unit processed.
1025 IF (STAMNT(L1
:L1
) == ' ') CYCLE
1026 IF (STAMNT(L1
:L1
) /= FIN(K1
:K1
) .AND
. &
1027 STAMNT(L1
:L1
) /= FINLC(K1
:K1
)) THEN
1031 IF (K1
> 3 .AND
. (L1
>= LENST
.OR
. STAMNT(L1
+1:LENST
) &
1033 IF (.NOT
.SYNERR
) THEN
1035 IF (LABEL
== 0) THEN
1036 WRITE (NOUT
, 1001) FIN
, NAME
1038 WRITE (NOUT
, 1002) LABEL
, FIN
, NAME
1042 ! Set counters for new program unit
1043 SYNTAX
= SYNTAX
.OR
. SYNERR
1049 IF (KNTCOM
/= 0) WRITE (NOUT
, '(A72)') (CBUF(72*L5
-71: &
1050 72*L5
) , L5
= 1 , KNTCOM
)
1061 ! If syntax error flag set, copy and take next statement
1064 WRITE (NOUT
, 1000) LAB
, CONTIN
, FIELD
1066 WRITE (NOUT
, 1006) CONTIN
, FIELD
1072 ! Compress blanks and insert blanks around special characters
1075 ! Handle Fortran keywords
1081 IF (BLANKS
) CALL KEYWORD(ASSIGN, SKIP
)
1084 IF (BLANKS
.AND
. ASSIGN .AND
. LABEL
== 0) GO
TO 14
1086 ! Have a valid statement which is not an END line or assignment
1087 ! Identify statement as DO
1094 CALL IDENTIFY(IRTCOD
)
1095 SELECT
CASE (IRTCOD
)
1101 IF (KNTDO
== NEST
) GO
TO 14
1103 LABLDO(KNTDO
+1) = LABLNO
1108 DO L5
= KNTDO
, 1 , -1
1109 IF (LABLDO(L5
) /= LABEL
) EXIT
1113 ! Replace CONTINUE by END DO
1114 KNTDO
= KNTDO
- NEND
1115 IF (NEND
== 1 .AND
. LENST
== 10 .AND
. STAMNT(:LENST
) == &
1117 STAMNT(:8) = 'END DO '
1121 ! Beginning of IF-block
1137 ! Beginning of ELSE-block
1146 ! Reformat statements and write
1147 14 CALL REFORM (FORM
, ELSEBL
)
1149 ! Set variables for next statement
1150 IF (NEWDO
) KNTDO
= KNTDO
+1
1151 IF (NEWIF
) KNTIF
= KNTIF
+1
1152 MXDO
= MAX(MXDO
, KNTDO
)
1153 MXIF
= MAX(MXIF
, KNTIF
)
1158 ! End of data. Last line must be an END.
1159 100 IF (LABEL
== 0) WRITE (NOUT
, 1001) FIN
, NAME
1160 IF (LABEL
/= 0) WRITE (NOUT
, 1002) LABEL
, FIN
, NAME
1162 IF (INTFL
) WRITE (NOUT
, '(6X, ''END INTERFACE'')')
1164 ! Note: if there is a syntax error, continued
1165 ! statements do not have a trailing &
1166 1000 FORMAT(I5
, A1
, A
)
1167 1001 FORMAT(TR6
, A3
,TR1
, A
)
1168 1002 FORMAT(I5
, TR1
, A3
,TR1
, A
)
1169 1006 FORMAT(TR5
, A1
, A66
)
1172 END SUBROUTINE PROGRAM_UNITS
1173 SUBROUTINE REFORM (FORM
, ELSEBL
)
1175 ! Performs reformatting and output of accepted statements
1182 INTEGER, PARAMETER :: LLIMIT
= LEN
-(LEN
/66-1)*6
1183 CHARACTER(LEN
=LEN
) :: OUT
1184 CHARACTER(LEN
= 1) :: AMP
1186 LOGICAL, INTENT(IN
) :: FORM
, ELSEBL
1188 integer :: ind
, ipnt
, l6
, l2
, l3
, l4
, lout
, idepth
, kntap
, kadd
, &
1191 ! If FORMAT statement, do not indent
1194 ! Remove the blanks before commas if no character string
1195 IF (BLNKFL
.AND
. INDEX(STAMNT(:LENST
), "'") == 0) THEN
1198 IND
= INDEX(STAMNT(IPNT
:LENST
), ' , ')
1200 IND
= IPNT
+ IND
- 1
1201 STAMNT(IND
:IND
+2) = ', '
1206 ! Reformat indented statement and write. If reformatting causes it
1207 ! to exceed LEN characters, it will be copied unchanged.
1208 IDEPTH
= MIN(KNTDO
+KNTIF
, MXDPTH
)
1209 IF (IDEPTH
== 0 .AND
. .NOT
.BLNKFL
) GO
TO 9
1210 IF (ELSEBL
) IDEPTH
= IDEPTH
-1
1213 1 IF (MOD(IPNT
, 66) == 1) THEN
1214 IF (IPNT
+65 > LEN
) GO
TO 9
1215 OUT(IPNT
:IPNT
+65) = ' '
1216 IPNT
= IPNT
+IDEPTH
*ISHIFT
1219 ! Find first non-blank character
1220 DO L2
= JPNT
, LENST
1221 IF (STAMNT(L2
:L2
) /= ' ') GO
TO 3
1230 ! Find first multiple blank (but not in a character string)
1233 IF (STAMNT(L3
:L3
) == "'") KNTAP
= 1-KNTAP
1234 IF (STAMNT(L3
:L3
+1) == ' ') THEN
1235 IF (KNTAP
== 0) GO
TO 5
1241 ! Have section with no multiple blanks. This can be copied to OUT
1242 ! if there is room on the current line. Otherwise cut the
1243 ! section after the non-alphanumeric character nearest to the end of
1244 ! the line, if one exists.
1245 ! An apostrophe and period are considered to be alphanumeric
1246 ! characters, in order to hold character strings,
1247 ! and real and logical constants together;
1248 ! underscores and dollars are so treated to handle common extensions,
1249 ! and the ** and // operators and real literal constants are treated.
1251 IF (L3
-L2
<= 66-MOD(IPNT
, 66)) GO
TO 8
1252 DO L4
= 66+L2
-MOD(IPNT
, 66) , L2
, -1
1253 IF (STAMNT(L4
:L4
) == ' ') GO
TO 7
1254 IF (LGE(STAMNT(L4
:L4
) , 'A') .AND
. LLE(STAMNT(L4
:L4
) , 'Z')) &
1256 IF(LGE(STAMNT(L4
:L4
), '0') .AND
. &
1257 LLE(STAMNT(L4
:L4
), '9')) CYCLE
1258 IF (STAMNT(L4
:L4
) == "'" .OR
. &
1259 STAMNT(L4
:L4
) == '_' .OR
. STAMNT(L4
:L4
) == '$' .OR
. &
1260 STAMNT(L4
:L4
) == '.') CYCLE
1261 IF (L4
/= LENST
) THEN
1262 IF (STAMNT(L4
:L4
+1) == '**' .OR
. &
1263 STAMNT(L4
:L4
+1) == '//' ) CYCLE
1265 IF(LGE(STAMNT(L4
+1:L4
+1), '0') .AND
. &
1266 LLE(STAMNT(L4
+1:L4
+1), '9')) THEN
1267 IF (STAMNT(L4
-1:L4
) == 'E+' .OR
. &
1268 STAMNT(L4
-1:L4
) == 'e+' .OR
. &
1269 STAMNT(L4
-1:L4
) == 'E-' .OR
. &
1270 STAMNT(L4
-1:L4
) == 'e-' .OR
. &
1271 STAMNT(L4
-1:L4
) == 'D+' .OR
. &
1272 STAMNT(L4
-1:L4
) == 'd+' .OR
. &
1273 STAMNT(L4
-1:L4
) == 'D-' .OR
. &
1274 STAMNT(L4
-1:L4
) == 'd-' ) CYCLE
1278 IF (LGE(STAMNT(L4
:L4
) , 'a') .AND
. LLE(STAMNT(L4
:L4
) , 'z')) &
1283 ! No break character found
1285 L4
= 66-MOD(IPNT
, 66)+L2
1291 IF (LOUT
> LEN
) GO
TO 9
1292 OUT(IPNT
:LOUT
) = STAMNT(L2
:L3
)
1293 IF (L3
== LENST
) GO
TO 10
1295 ! Set pointers for next section of statement
1297 IF (KADD
== 1 .AND
. MOD(IPNT
, 66) /= 1 .OR
. MOD(IPNT
, 66) &
1298 >= 60) IPNT
= ((IPNT
+65)/66)*66+1
1299 IF (MOD(IPNT
, 66) == 0) IPNT
= IPNT
+1
1301 IF (KADD
== 0) JPNT
= JPNT
+1
1304 ! Copied statement (if adding 6 cols. to initial line would cause
1305 ! total length to exceed 2640, must start it in col.1)
1306 9 LENST
= LEN_TRIM(STAMNT(:LENST
))
1307 IF (LENST
> 66) THEN
1312 IF (LABEL
/= 0) THEN
1313 WRITE (NOUT
, 1003) LABEL
, STAMNT(:MIN(LENST
, 66)), AMP
1315 IF (LENST
< LEN
-6) THEN
1316 WRITE (NOUT
, 1004) STAMNT(:MIN(LENST
,66)), AMP
1318 WRITE (NOUT
, '(A,A1)') STAMNT(:MIN(LENST
, 66)), AMP
1321 IF (LENST
> 66) WRITE (NOUT
, 1005) &
1322 &('&', STAMNT(66*L6
-65:66*L6
) , L6
= 2 , (LENST
+65)/66)
1325 ! Write OUT to output unit
1326 10 LOUT
= LEN_TRIM(OUT(:LOUT
))
1332 IF (LABEL
/= 0) THEN
1333 WRITE (NOUT
, 1003) LABEL
, OUT(:MIN(LOUT
, 66)), AMP
1335 WRITE (NOUT
, 1004) OUT(:MIN(LOUT
, 66)), AMP
1338 ! An & is required in col. 6 if statement has more than 2412
1339 ! characters, otherwise total length including cols. 1-6 will
1340 ! exceed 2640. Also if making interface blocks, in order to be
1341 ! compatible with both old and new source forms.
1343 IF (LOUT
> LLIMIT
.OR
. INTFL
) THEN
1348 WRITE (NOUT
, 1005) (AMP
, OUT(66*L5
-65:66*L5
) , L5
= 2 , ( &
1352 ! Write any comments following statement
1353 11 IF (KNTCOM
/= 0) THEN
1354 WRITE (NOUT
,'(A72)') (CBUF(72*L5
-71:72*L5
) , L5
= 1 , KNTCOM
)
1358 1003 FORMAT(I5
, TR1
, A
, A
)
1359 1004 FORMAT(TR6
, A
, A
)
1360 1005 FORMAT(TR5
, A
, A
:'&' )
1363 END SUBROUTINE REFORM
1364 SUBROUTINE SPECIAL(L3
, NEXT
, BUFFER
, NKEY
, KEYS
, KEYSLC
, &
1367 ! Special treatment for peculiar Fortran syntax
1374 INTEGER, PARAMETER :: NUMLEN
= 5
1376 CHARACTER(LEN
=*), INTENT(OUT
) :: BUFFER
1377 INTEGER, INTENT(IN
) :: NKEY
1378 INTEGER, INTENT(IN
), dimension(:) :: LK
1379 CHARACTER(LEN
=*), INTENT(IN
), dimension(:) :: KEYS
, KEYSLC
1380 CHARACTER(LEN
=32) :: NAMEOF
1381 CHARACTER(LEN
=NUMLEN
) :: NUMBER
1383 INTEGER, INTENT(IN OUT
) :: L3
, NEXT
1384 LOGICAL, INTENT(IN
), dimension(:) :: FOLLOW
1386 integer :: ind
, l20
, istar
, lparen
, napos
, ndigit
,&
1387 nparen
, l10
, ilp
, isss
, limit
, name_length
1391 ! Deal with labelled DO WHILE
1393 IND
= index(STAMNT(:LENST
), 'WHILE')
1394 IF (IND
== 0) IND
= index(STAMNT(:LENST
), 'while')
1396 IF(LGE(STAMNT(IND
-1:IND
-1), '0') .AND
. &
1397 LLE(STAMNT(IND
-1:IND
-1), '9')) &
1398 STAMNT(IND
:IND
+5) = ' WHILE'
1403 ! Deal with IMPLICIT with non-standard length specifiers
1405 IF (index(STAMNT(:LENST
), '*') /= 0) THEN
1407 ! first, CHARACTER*(len)
1408 11 IND
= index(STAMNT(:LENST
), 'CHARACTER * (')
1409 IF (IND
== 0) IND
= index(STAMNT(:LENST
),'character * (')
1411 STAMNT(IND
+10:IND
+10) = ' '
1419 IF (STAMNT(L10
:L10
) == "'") THEN
1421 ELSE IF (STAMNT(L10
:L10
) == '(') THEN
1422 IF (NAPOS
== 0) NPAREN
= NPAREN
+ 1
1423 ELSE IF (STAMNT(L10
:L10
) == ')') THEN
1424 IF (NAPOS
== 0) NPAREN
= NPAREN
- 1
1425 ELSE IF (STAMNT(L10
:L10
) == '*') THEN
1426 IF (NPAREN
== 0) THEN
1427 STAMNT(L10
:L10
+1) = ' ('
1428 ILP
= index(STAMNT(L10
+2:LENST
), '(')
1433 STAMNT(L10
+ILP
:L10
+ILP
) = ')'
1435 IF (STAMNT(L10
+1:L10
+3) == '(4)') THEN
1436 IF (STAMNT(L10
-5:L10
-5) /= 'C' .AND
. &
1437 STAMNT(L10
-5:L10
-5) /= 'c') &
1438 STAMNT(L10
+1:L10
+3) = ' '
1439 ELSE IF (STAMNT(L10
-2:L10
+3) == 'X (8)' .OR
. &
1440 STAMNT(L10
-2:L10
+3) == 'x (8)')THEN
1441 STAMNT(L10
+1:L10
+3) = ' '
1451 ! An ASSIGN label must be followed by a blank and a * specifier
1452 ! converted to (...)
1453 IF(L3
== 1 .AND
. STAMNT(:7 ) == 'ASSIGN ' .OR
. &
1454 L3
== 5 .AND
. STAMNT(:11) == 'CHARACTER *' .OR
. &
1455 L3
== 8 .AND
. STAMNT(:9 ) == 'COMPLEX *' .OR
. &
1456 L3
== 27.AND
. STAMNT(:9 ) == 'INTEGER *' .OR
. &
1457 L3
== 29.AND
. STAMNT(:9 ) == 'LOGICAL *' .OR
. &
1458 L3
== 36.AND
. STAMNT(:6 ) == 'REAL *' ) THEN
1461 ELSE IF (L3
< 30) THEN
1467 ! Extract the length parameter
1470 DO L20
= ISSS
, LENST
1471 IF(STAMNT(L20
:L20
) == ' ') CYCLE
1472 NUMBER(:1) = STAMNT(L20
:L20
)
1473 IF(LGE(STAMNT(L20
:L20
),'0') .AND
. LLE(STAMNT(L20
:L20
),'9') &
1479 21 DO NEXT
= L20
+1, LENST
1480 IF(STAMNT(NEXT
:NEXT
) == ' ') CYCLE
1481 IF(LLT(STAMNT(NEXT
:NEXT
), '0') .OR
. LGT(STAMNT(NEXT
:NEXT
), &
1484 IF (NDIGIT
> NUMLEN
) THEN
1488 NUMBER(NDIGIT
:NDIGIT
) = STAMNT(NEXT
:NEXT
)
1495 ! Insert the blank or parentheses
1496 19 IF (LENST
>= LEN
-1) THEN
1500 BUFFER(NEXT
:LENST
) = STAMNT(NEXT
:LENST
)
1503 STAMNT(NEXT
:NEXT
+3) = ' TO '
1504 STAMNT(NEXT
+4:LENST
) = BUFFER(NEXT
+2:LENST
-2)
1507 STAMNT(NEXT
:NEXT
) = ' '
1508 STAMNT(NEXT
+1:LENST
) = BUFFER(NEXT
:LENST
-1)
1509 IF (L3
/= 5.AND
. NDIGIT
== 1 .AND
. NUMBER(:1) == '4') THEN
1510 STAMNT(NEXT
-4:NEXT
-1) = ' '
1511 ELSE IF (L3
== 8.AND
.NDIGIT
== 1 .AND
. NUMBER(:1) == '8') &
1513 STAMNT(NEXT
-4:NEXT
-1) = ' '
1515 STAMNT(NEXT
-3-NDIGIT
:NEXT
-1) = '('//NUMBER(:NDIGIT
)//')'
1521 1 IF(L3
== 5 .AND
. STAMNT(:18) == 'CHARACTER * ( * )') THEN
1526 ! IF statement may be followed by a keyword
1527 2 IF (L3
== 24 ) THEN
1531 IF (STAMNT(NEXT
:NEXT
) == "'") NAPOS
= 1 - NAPOS
1532 IF (NAPOS
== 1) CYCLE
1533 IF (STAMNT(NEXT
:NEXT
) == '(' ) LPAREN
= LPAREN
+1
1534 IF (STAMNT(NEXT
:NEXT
) == ')' ) LPAREN
= LPAREN
-1
1535 IF (LPAREN
== 0) GO
TO 5
1540 IF (FOLLOW(L3
) .AND
.(STAMNT(NEXT
+1:NEXT
+LK(L3
)) == KEYS(L3
)&
1541 .OR
. STAMNT(NEXT
+1:NEXT
+LK(L3
)) == KEYSLC(L3
)&
1543 NEXT
= NEXT
+LK(L3
)+1
1544 IF(L3
== 1) IFASSIGN
= .TRUE
.
1551 IF(STAMNT(NEXT
+1:NEXT
+8) == 'FUNCTION' .OR
. &
1552 STAMNT(NEXT
+1:NEXT
+8) == 'function') THEN
1554 call name_of(nameof
, stamnt(next
:lenst
), name_length
)
1555 NAME
= 'FUNCTION'//NAMEOF(:name_length
)
1559 LIMIT
= index(STAMNT(:LENST
), '(')
1560 IF (LIMIT
/= 0) THEN
1561 ISTAR
= index(STAMNT(:LIMIT
), '*')
1562 IF (ISTAR
/= 0) THEN
1563 NDIGIT
= LIMIT
- ISTAR
-3
1564 IF (NDIGIT
> NUMLEN
) THEN
1568 NUMBER(:NDIGIT
) = STAMNT(ISTAR
+2:LIMIT
-2)
1569 STAMNT(NEXT
-5+NDIGIT
:LIMIT
-2) = &
1570 'FUNCTION'//NAME(10:ISTAR
-NEXT
+8)
1571 STAMNT(NEXT
-8:NEXT
-6+NDIGIT
) = &
1572 '('//NUMBER(:NDIGIT
)//') '
1573 IF (NDIGIT
== 1 .AND
. NUMBER(:1) == '4') THEN
1574 STAMNT(NEXT
-8:NEXT
-5) = ' '
1575 ELSE IF (NDIGIT
== 1 .AND
. NUMBER(:1) == '8'.AND
.&
1576 (STAMNT(7:7) == 'X'.OR
.STAMNT(7:7) == 'x')) THEN
1577 STAMNT(NEXT
-8:NEXT
-5) = ' '
1579 NEXT
= NEXT
+ 3 + NDIGIT
1591 9 IF (LENST
>= LEN
-2) THEN
1595 BUFFER(NEXT
:LENST
) = STAMNT(NEXT
:LENST
)
1597 STAMNT(NEXT
:NEXT
) = ' '
1598 STAMNT(NEXT
+1:LENST
) = BUFFER(NEXT
:LENST
-1)
1600 ! ASSIGN may follow IF
1601 IF(.NOT
.IFASSIGN
) GO
TO 99
1602 NEXT
= index(STAMNT(:LENST
), 'TO')
1603 IF (NEXT
== 0) NEXT
= index(STAMNT(:LENST
), 'to')
1609 STAMNT(NEXT
:NEXT
+3) = ' TO '
1610 STAMNT(NEXT
+4:LENST
) = BUFFER(NEXT
+1:LENST
-3)
1613 END SUBROUTINE SPECIAL
1616 ! To prepare for PROGRAM_UNITS
1620 CHARACTER(LEN
=16) :: NAME
1622 ! Prompt for interactive use
1623 WRITE (*,'(" Type name of file, shift, max. indent level, T or F &
1624 &for blank treatment,",/ " T or F for interface blocks only.")')
1625 WRITE (*,'(" For simple use type only the name of the file ", &
1626 &"followed by a slash (/) and RETURN.",/ &
1627 &" Note that the name should be given WITHOUT extension!")')
1629 ! Does standard input unit contain an input record
1636 READ (* , * , END = 1 , ERR
= 1) NAME
, ISHIFT
, MXDPTH
, &
1639 ! If record present, check input values are reasonable
1640 ISHIFT
= MIN(MAX(ISHIFT
, 0) , 10)
1641 MXDPTH
= MIN(MAX(MXDPTH
, 0) , 36/MAX(ISHIFT
,1))
1642 IF (INTBFL
.AND
..NOT
.BLANKS
) WRITE (*, '('' Interface block proces&
1643 &sing cancelled as blank processing not requested'')')
1644 INTBFL
= BLANKS
.AND
.INTBFL
1647 ! Set default values
1653 2 OPEN (UNIT
=NIN
, FILE
=TRIM(NAME
)//'.f', ACTION
='READ')
1654 OPEN (UNIT
=NOUT
, FILE
=TRIM(NAME
)//'.f90', ACTION
='WRITE')
1656 ! Print values to be used
1657 Write (*,'(" Loop bodies will be indented by",I3/ &
1658 & " Maximum indenting level is ",I3)') &
1660 IF (BLANKS
) WRITE (*, &
1661 '(" Significant blank proccessing requested")')
1662 IF (INTBFL
) WRITE (*, &
1663 '('' Only interface blocks will be produced'')')
1664 IF (INTBFL
) WRITE (NOUT
, '(6X, ''INTERFACE'')')
1666 CALL SYSTEM_CLOCK(TIME0
)
1668 END SUBROUTINE START
1669 SUBROUTINE TERMINATE( )
1671 ! To print the final summary
1677 integer :: itick
, itime
1679 CALL SYSTEM_CLOCK(ITIME
, ITICK
)
1681 WRITE (*,'(" Processing complete in ", F7.3, " seconds")') &
1682 REAL(ITIME
-TIME0
)/REAL(ITICK
)
1683 WRITE (*,'(" Maximum depth of DO-loop nesting ",I3/ &
1684 & " Maximum depth of IF-block nesting",I3/ &
1685 &" No. of lines read ",I17/" No. of program units read ",I8/ &
1686 & " Global syntax error flag",L12)') &
1687 MXDO
, MXIF
, KARD
, KNTPU
, SYNTAX
1689 IF (OVFLW
) WRITE(*, '(" At least one statement was too long to h&
1690 &ave a necessary blank added")')
1691 IF (NONSTD
) WRITE (*, '(" At least one statement began with a no&
1692 &n-standard keyword")')
1695 END SUBROUTINE TERMINATE
1696 END MODULE ALL_PROCEDURES
1704 ! Process the lines of program units
1705 CALL PROGRAM_UNITS( )
1707 ! Print some statistics