[comp.os.vms] Fpretty.3_of_3

GHC@NIHKLMB.BITNET (Gerson H Cohen) (08/09/88)

$Part3:
$ File_is="FPRETTY1.FOR"
$ Check_Sum_is=271587105
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
Xc
Xc     Program to read a FORTRAN program and produce
Xc     an indented listing showing levels of nesting.
Xc
Xc     This program was originally written by Dr. Ann Copeland
Xc     of the Georgia Tech Research Institute.  Mark Paulk at
Xc     SDC Huntsville made certain modifications (DCL tables,
Xc     /NOLIST format, etc.).  For info on the command line
Xc     interface, see SET COMMAND and Utilities Manual section
Xc     on the DCL editor.
Xc
Xc     MODS:
Xc     linein extended to 132 characters to allow for long comments
Xc     problem was fortran variable mismatch on read with long comment
Xc     MCP 25 Oct 82
Xc     for lines longer than 72 check for comment before splitting and
Xc     making continuation
Xc     MCP 26 Oct 82
Xc     add check for ! type of comments - dont continue them
Xc     MCP 1 Nov 82
Xc     add treatment of continue following a tab character
Xc     GHC 8 Nov 83
Xc     fix up finding file type when directory string is present
Xc     force result file to be in sys$disk:[]
Xc     GHC 9 Nov 83
Xc     recode where possible to use character functions
Xc     treat D in col 1 as a comment
Xc     GHC 10 Nov 83
Xc
Xc     Assumption:
Xc     The .FOR file submitted as input has
Xc     compiled successfully.
Xc
X      logical this_is_a_comment
X      logical success
X      logical end_flag
X      character source_file*256,default_type*6
X      integer cli$get_value,cli$present
Xc
Xc     Functions.
Xc
X      integer dedent_word
X      logical compare
X      logical space
Xc
Xc     Commons.
Xc
X      common/line/linein,lineout,in_length,out_length
X      character linein*132,lineout*132
X      integer in_length,out_length
Xc
X      common/split/line_continue,continue_length,start
X      character line_continue*132
X      integer continue_length,start
Xc
X      common/listing/comment_flag,list_flag,indenter
X      logical comment_flag,list_flag
X      character indenter*3
Xc
X      common/error/err_num,num_parens,quote_out
X      integer err_num,num_parens
X      logical quote_out
Xc
X      common/chars/blank,zero
X      integer blank,zero
Xc
Xc     Datas.
Xc
X      character letter_c,letter_d
X      data letter_c/'C'/,letter_d/'D'/
Xc
Xc     Start of executable code.
Xc
Xc     Initialization.
Xc
X      end_flag = .false.
X      indent = 0
X      next_line = 0
X      stack_pointer = 0
X      err_num = 0
X      blank = ichar(' ')
X      zero = ichar('0')
Xc
Xc     Examine command line for source file name.
Xc
X      call cli$get_value('P1',source_file)
X      i = index(source_file,' ') - 1
X      default_type = '.FOR  '
X      open (unit=5,file=source_file(1:i),defaultfile=default_type,
X     1      status='old',readonly,err=30)
Xc
Xc     so what did we open?
Xc
X      inquire (unit=5,name=source_file)
Xc
X      list_flag = cli$present('LIST')
Xc
Xc     Determine if /LIST option present.
Xc
X      if (list_flag) then
X         default_type = '.LIS;0'
X      else
X         default_type = '.FOR;0'
X         indenter(1:1) = ' '
X      end if
X      i = index(source_file,' ') - 1
X      open (unit=4,file=default_type,defaultfile=source_file(1:i),
X     1      status='new',carriagecontrol='list',err=32)
Xc
Xc     Determine if /COMMENT_INDENT option present.
Xc
X      comment_flag = .not. cli$present('COMMENT_INDENT')
Xc
Xc     Start reading input file on unit FOR005.
Xc
X      read(5,10000,end=20) in_length,linein
X10000 format(q,a)
X      do while (.true.)
Xc
Xc        get rid of trailing blanks
Xc
X         do while (in_length.gt.0 .and.
X     &      space(linein(in_length:in_length)))
X            in_length = in_length - 1
X         end do
Xd        write(6,10010) in_length
X10010    format(' in main in_length = ',i3)
Xc
Xc        Check for blank line.
Xc
X         if (in_length.gt.0) then
Xc
Xc           note if we have a comment
Xc
X            this_is_a_comment =
X     &      compare(linein(1:1),letter_c) .or.
X     &      compare(linein(1:1),letter_d)
Xc
Xc           Strip leading spaces.
Xc           Process comment lines only if /COMMENT_INDENT
Xc
X            if (.not.comment_flag .or.
X     &      (comment_flag .and. .not.this_is_a_comment)) then
X               call place(this_is_a_comment)
Xc
Xc              Check to see if an unprinted error was encountered
Xc              on the last statement.
Xc              If so, then check to see if this is a continued line
Xc              which might resolve error.
Xc
X               if (err_num.ne.0) then
X                  if (space(linein(6:6))) then
X                     call error(err_num)
X                     err_num = 0
X                  end if
Xc
Xc                 Check to see if this line should be dedented.
Xc                 Dedentation is defined to be the inverse of indentation.
Xc
X               else
X                  if ((in_length.ge.7) .and.
X     &            .not.this_is_a_comment) then
X                     indent = indent + dedent_word(end_flag)
X                  end if
X               end if
X            end if
Xc
Xc           Check to see if next line should be indented one more level.
Xc
X            if ((in_length.ge.7) .and. .not.this_is_a_comment)
X     &      call indent_word(next_line)
Xc
Xc           Write out line with proper levels of indentation on FOR004.
Xc
X            if ((in_length.le.6) .or.
X     &      (indent.le.0 .and. in_length.lt.72) .or.
X     &      (comment_flag .and. this_is_a_comment)) then
X               write(4,10030) linein(1:in_length)
X            else
Xc
Xc              Move line over for indentation before writing.
Xc              Don't try to continue comments.
Xc
X   10          if (indent.gt.0) then
X                  call nest(indent)
X               else
X                  out_length = in_length
X                  lineout(1:out_length) = linein(1:in_length)
X               end if
X               if ((out_length.gt.72) .and. .not.list_flag .and.
X     &         .not.this_is_a_comment) then
X                  write(6,10020) lineout(1:out_length)
X10020             format(' %length>72 ->'/x,a)
X                  call split(success)
X                  if (success) then
X                     write(4,10030) lineout(1:out_length)
X10030                format(a)
X                     linein(1:continue_length) =
X     &               line_continue(1:continue_length)
X                     in_length = continue_length
X                     go to 10
X                  else
X                     write(4,10030) linein(1:in_length)
X                  end if
X               else
X                  write(4,10030) lineout(1:out_length)
X               end if
X            end if
Xc
Xc           Update count of indentation level based on last line read.
Xc
X            indent = indent + next_line
X            next_line = 0
X            if (indent.lt.0) then
X               call error(1)
X               indent = 0
X            end if
X            if (indent.gt.17) call error(6)
X         else
X            write(4,10030)
X         end if
Xc
Xc        Read next line and see if it begins a new program unit.
Xc
X         read(5,10000,end=20) in_length,linein
X         if (end_flag) then
X            if (list_flag) then
X               write (4,'(////)')
X            end if
X            end_flag = .false.
X            indent = 0
X            next_line = 0
X            stack_pointer = 0
X            err_num = 0
X         end if
X      end do
X   20 call exit
X   30 inquire (file=source_file(1:i),defaultfile=default_type,
X     1         name=source_file)
X      go to 34
X   32 inquire (file=default_type,defaultfile=source_file(1:i),
X     1         name=source_file)
X   34 write (6,'(a)') ' Error opening file: '//
X     1                  source_file(1:index(source_file,' ')-1)
X      call exit
X      end
Xc
Xc     Convert statement label in columns 1-5 into integer value.
Xc     Return 0 (zero) if all spaces.
Xc
X      integer function label()
Xc
X      character save*5
Xc
Xc     Function.
Xc
X      logical space
Xc
Xc     Commons.
Xc
X      common/line/linein,lineout,in_length,out_length
X      character linein*132,lineout*132
X      integer in_length,out_length
Xc
Xc     Executable code.
Xc
Xd     write(6,10000)
X10000 format(' in label')
Xc
X      i = 1
X      do while (i.le.5 .and. space(linein(i:i)))
X         i = i + 1
X      end do
X      j = 0
X      do while (i.le.5 .and. number(linein(i:i)))
X         j = j + 1
X         save(j:j) = linein(i:i)
X         i = i + 1
X      end do
X      if (j.gt.0) then
Xd        write (6,10010) save(1:j)
X10010    format(' save = ',a)
X         read (save(1:j),10020) label
X10020    format (i<j>)
X      else
X         label = 0
X      end if
X      return
X      end
Xc
Xc     Subroutine to determine if the next line should be
Xc     indented one more level.
Xc
X      subroutine indent_word(next_line)
Xc
X      integer last
Xc
Xc     Functions.
Xc
X      logical match
X      integer do_label
X      logical space,next_non_blank
Xc
Xc     Commons.
Xc
X      common/line/linein,lineout,in_length,out_length
X      character linein*132,lineout*132
X      integer in_length,out_length
Xc
X      common/stack/do_stack,stack_pointer
X      integer do_stack(20),stack_pointer
Xc
X      common/error/err_num,num_parens,quote_out
X      integer err_num,num_parens
X      logical quote_out
Xc
Xc     Datas.
Xc
Xc     List of possible words after which indentation occurs.
Xc     IF (THEN)
Xc     ELSE
Xc     DO (includes DO WHILE)
Xc     STRUCTURE
Xc     UNION
Xc     MAP
Xc
X      character if*2,then*4,else*4,do*2,structure*9,union*5,map*3
X      data if/'IF'/
X      data then/'THEN'/
X      data else/'ELSE'/
X      data do/'DO'/
X      data structure/'STRUCTURE'/
X      data union/'UNION'/
X      data map/'MAP'/
Xc
Xc     Executable code.
Xc
Xd     write(6,10000)
X10000 format(' in indent')
Xd     type *,in_length,' ',linein(1:in_length)
X      next_line = 0
Xc
Xc     Check for IF or continued IF.
Xc
X      if ((err_num.ne.0) .or. match(7,if,2)) then
Xc
Xc        Last word on executable part of statement must be THEN.
Xc
X         call log_expr(last)
X         if (((last+3).le.in_length) .and. (err_num.eq.0)) then
X            if (match(last,then,4)) then
X               next_line = 1
X            end if
X         end if
Xc
Xc        Check for ELSE.
Xc
X      else if (match(7,else,4)) then
X         next_line = 1
Xc
Xc        Check for DO.
Xc
X      else if (match(7,do,2).and.space(linein(9:9))
X     1             .and..not.next_non_blank(9,'=')) then
X         next_line = 1
Xc
Xc        One entry on stack for each DO.
Xc        Entry is statement label for DO-loops with labels.
Xc        Entry is 0 (zero) for DO-loops without labels and
Xc        DO-WHILEs.
Xc
Xc        Stack statement label.
Xc
X         stack_pointer = stack_pointer + 1
X         do_stack(stack_pointer) = do_label()
Xc
Xc        Check for STRUCTURE
Xc
X      else if (match(7,structure,9).and.next_non_blank(16,'/')) then
X         next_line = 1
Xc
Xc        Check for UNION
Xc
X      else if (match(7,union,5).and.
X     1        (in_length.eq.11.or.next_non_blank(12,'!'))) then
X         next_line = 1
Xc
Xc        Check for MAP
Xc
X      else if (match(7,map,3).and.
X     1        (in_length.eq.9.or.next_non_blank(10,'!'))) then
X         next_line = 1
X      end if
X      return
X      end
Xc
Xc     Function to compare next non-blank.
Xc     Absence of a non-blank is also true.
Xc
X      logical function next_non_blank(start,character)
X      integer start
X      character*1 character
Xc
Xc     Commons.
Xc
X      common/line/linein,lineout,in_length,out_length
X      character linein*132,lineout*132
X      integer in_length,out_length
Xc
X      logical space
Xc
Xc     Executable code.
Xc
Xd     write(6,10000)
X10000 format(' in next_non_blank')
X      i = start
X      do while (i.le.in_length.and.space(linein(i:i)))
X`009 i = i + 1
X      end do
X      next_non_blank = i.gt.in_length.or.linein(i:i).eq.character
X      return
X      end
Xc
Xc     Function to compare two strings for match.
Xc     The string called WORD is required upper case.
Xc
X      logical function match(start,word,word_length)
X      integer start
X      character word*(*)
X      integer word_length
Xc
Xc     Common.
Xc
X      common/line/linein,lineout,in_length,out_length
X      character linein*132,lineout*132
X      integer in_length,out_length
Xc
X      character line_work*132
Xc
Xc     Executable code.
Xc
Xd     write(6,10000)
X10000 format(' in match')
X      call str$upcase(line_work,linein(start:start+word_length-1))
X      match = line_work(1:word_length).eq.word(1:word_length)
X      return
X      end
Xc
Xc     Function to compare two characters for match.
Xc
X      logical function compare(letter,upper_case_value)
X      character letter,upper_case_value
Xc
X      character lower_case_value
Xc
Xc     Common.
Xc
X      common/chars/blank,zero
X      integer blank,zero
Xc
Xc     Executable code.
Xc
Xd     write(6,10000)
X10000 format(' in compare')
X      lower_case_value = char(ichar(upper_case_value)+blank)
X      compare = ((letter.eq.upper_case_value) .or.
X     &(letter.eq.lower_case_value))
X      return
X      end
$ GoSub Convert_File
$ Exit