[Shootout-list] Fortran count-words

Simon Geard simon@whiteowl.co.uk
Wed, 23 Mar 2005 23:51:39 +0000


This is a multi-part message in MIME format.
--------------040401040505080102070501
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

My first go at this test. Could be streamlined when time permits! Please 
add it when you can.

Thanks,

Simon Geard


--------------040401040505080102070501
Content-Type: text/plain;
 name="count-words.f90"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="count-words.f90"

! The Great Computer Language Shootout
! http://shootout.alioth.debian.org/
!
! contributed by Simon Geard, 27/02/2005
!
! ifort count-words.f90 -O3 -static-libcxa -o count-words
!
!
program countWords
  implicit none
  integer, parameter :: rsize = 64

  character(len=8) argv
  character(len=rsize), dimension(:), allocatable :: line     ! A line of text
  character(len=rsize), dimension(:), allocatable :: work
  character(len=rsize)                            :: str_blk  ! A block of chars read from the line
  integer                                         :: bline    ! The number of rsize blocks used in a line of chars

  integer :: nlines = 0 ! Line counter
  integer :: nwords = 0 ! Word counter
  integer :: nchars = 0 ! Char counter
  integer :: i, nread

  ! Read and count
  allocate(line(100)) ! Allocates 100 x rsize characters for a line
  readFile: do
     bline = 0
     readLine: do
        bline = bline+1
        read(5,fmt='(a)',end=100,eor=10,size=nread,advance='no') str_blk
        call expandLine
        line(bline) = str_blk(1:nread)
        nchars = nchars + nread
     end do readLine
10   continue
     call expandLine
     if (nread == 0) then
        bline = bline - 1
     else
        line(bline) = str_blk(1:nread)
     end if
     nchars = nchars + nread
     if (bline > 0) then
        nwords = nwords + numWords(line,bline)
     end if
     nlines = nlines + 1
  end do readFile
100 continue
  nchars = nchars + nlines ! Have to add the number of nl characters
  write(*,'(2(i0,a),i0)') nlines, ' ', nwords, ' ', nchars
  stop

contains
  subroutine expandLine
    if (bline > size(line)) then ! More space needed for line
       ! Allocate more memory
       allocate(work(size(line)))
       work = line
       deallocate(line)
       allocate(line(2*size(work)))
       line = work
       deallocate(work)
    end if
  end subroutine expandLine

  integer function numWords(l_line, bline)
    character(len=*), dimension(:), intent(in) :: l_line
    integer, parameter :: tab = 9
    integer, intent(in) :: bline
    integer i, j
    logical :: ingap, started
    character(len=rsize) :: line
    integer :: ng

    ingap = .false.
    ng = 0
    started = .false.

    ! Search in the 1st block
    line = l_line(1)
    do i=1,len(line)
       if (.not. started) then
          started = (line(i:i) /= ' ')

       elseif ( .not. ingap .and. (line(i:i) .eq. ' ' .or. line(i:i) .eq. achar(tab))) then
          ng = ng + 1
          ingap = .true.

       elseif (ingap .and. ischar(line(i:i))) then
          ingap = .false.

       end if
    end do
    if (bline == 1) then
       if (ingap) ng = ng - 1
       numWords = ng + 1
       return
    end if

    ! Do the next n-2 blocks
    do j=2,bline-1
       line = l_line(j)
       do i=1,len(line)
          if (.not. started) then
             started = (line(i:i) /= ' ')

          elseif (.not. ingap .and. (line(i:i) .eq. ' ' .or. line(i:i) .eq. achar(tab))) then
             ng = ng + 1
             ingap = .true.

          elseif (ingap .and. ischar(line(i:i))) then
             ingap = .false.
          end if
       end do
    end do

    ! Do the last block
    line = trim(l_line(bline)) ! Ignore trailing wspace here
    do i=1,len(trim(line))
       if (.not. started) then
          started = (line(i:i) /= ' ')

       elseif (.not. ingap .and. (line(i:i) .eq. ' ' .or. line(i:i) .eq. achar(tab))) then
          ng = ng + 1
          ingap = .true.

       else if (ingap .and. ischar(line(i:i))) then
          ingap = .false.
       end if
    end do
    numWords = ng + 1
  end function numWords

  logical function ischar(c)
    character, intent(in) :: c
    ischar = (iachar(c) > 32 .and. iachar(c) < 127)
  end function ischar

end program countWords

--------------040401040505080102070501--