Article 5892 of alt.sources:
Path: jac.zko.dec.com!pa.dec.com!decwrl!hookup!news.mathworks.com!gatech!purdue!haven.umd.edu!cs.umd.edu!ra.nrl.navy.mil!mitch.nrl.navy.mil!grunes
From: grunes@news.nrl.navy.mil (Mitchell R Grunes)
Newsgroups: alt.sources,comp.lang.c
Subject: diagramc: Simple Diagrammer for C Language Programs
Date: Fri, 2 Jun 1995 19:37:33 GMT
Organization: NRL Code 8140
Lines: 387
Message-ID: <grunes.234.802121853@news.nrl.navy.mil>
NNTP-Posting-Host: mitch.nrl.navy.mil
Xref: jac.zko.dec.com alt.sources:5892 comp.lang.c:82302

Archive-name: diagramc
Submitted-by: grunes@nrlvax.nrl.navy.mil (Mitchell R Grunes)

********diagramc: Simple Diagrammer for C Language Programs********

This is an update, with minor improvements.

Sorry, little or no help can be provided for this program--
and I would need an example of where it failed.
DO NOT POST responses to newsgroups--especially not alt.sources.

I include 2 files:
  diagramc.for     Fortran language source code.
  diagramc.bat     Sample procedure to run without answering
                   questions.  Would only work under MS-DOS,
                   and if executable were in c:\gsar89\grunes
---diagramc.for--------------CUT HERE-----------------------------
        program diagramc        !Diagrammer for C

c EXAMPLE OF OUTPUT:

c     +------ I_Hate_C() {                             |   1
c     |+------- if (You_Like(C)) {                     |   2
c     ||          BoyOrGirl=Bad;                       |   3
c     ||+---- #ifdef SMART                             |   4
c     |||         ReEducate();                         |   5
c     ||+---- #endif                                   |   6
c     |+------- } else {                               |   7
c     ||          BoyOrGirl=Good;                      |   8
c     |+------- }                                      |   9
c     +------ }                                        |  10

c Diagrams C language {} constructs, #if--#elif--#Endif, case and default,
c  and puts a * next to goto, break, continue, exit and return.

c Program by Mitchell R Grunes, ATSC/NRL (grunes@nrlvax.nrl.navy.mil).
c Revision date: 6/2/95.
c If you find it useful, please send me an e-mail comment--
c  but do NOT send money.

c This program was written in FORTRAN, the One True Language.
c (For this reason, people who mostly program in C will probably be
c  unwilling to use this program, even as a utility.)

c Note--this is a quick and dirty attempt--may not always work quite right.
c  It can also be confused if an INCLUDE block contains a structure that
c    begins inside and ends outside (or vice-versa); likewise with
c    #if...#endif blocks (if you are diagramming them).

c It is assumed that no fortran carriage control exists on the output
c  file, unless screen output is specified.

c I hope this works for you, but bear in mind that nothing short of
c  a full-fledged language parser could really do the job.  Perhaps
c  worth about what you paid for it.    (-:

c Versions: To diagram  Fortran: diagramf.for
c                       IDL:     diagrami.for
c                       C:       diagramc.for
c MS-DOS procedures to call above programs without asking so many questions,
c  append output to file diagram.out:
c                       Fortran: diagramf.bat
c                       IDL:     diagrami.bat
c                       C:       diagramc.bat

c The diagramc version differs from the diagramf and diagrami versions in
c  that a space is always left after diagramming lines.  This is because
c  C lines can start with a "-".

        character*160 a,b,bsave
        character*132 filnam,filnam2
        character*16 aa
        character*5 form
        character*8 fm
        character*1 c
        logical fout
        logical find
        external find
        common icol
        print*,'C source filename?'
        read(*,1)filnam
1       format(a132)
        open(1,file=filnam,status='old')
        print*,'Output file (blank=screen)?'
        read(*,1)filnam2
        fout=filnam2.gt.' '
        if(fout)open(2,file=filnam2,status='unknown')
                                !ASCII 12 is a form feed
        if(fout)write(2,*)char(12),
     &   '=============--',filnam(1:LenA(filnam)),'--============='
        print*,'column for line #(76 for 80 col screen, 0 for none)?'
        iline=0
        read*,iline
        if (iline.gt.8)iline=iline-8
        print*,'Notate comments with = (0=no, 1=yes):'
        read*,inotate
        print*,'Try to diagram pre-processor directives (1=yes):'
        print*,'(If 1, program will fail if pre-processor directives'
        print*,' and {} clauses do not nest.  BUT, most of the time'
        print*,' they do nest, and you want 1.):'
        read*,ipreproc
        aa='| | | | | | | | '
        i3=0                            !# of nest levels after current line
        nline=0
        icomment=0                      !not inside comment
        iunit=1
10      a=' '
        read(iunit,11,end=99)a
11      format(a160)
        nline=nline+1
        fm=' '
        write(fm,'(i5)')nline
        form=fm
        if(nline/100*100.eq.nline.and.fout)print*,'Line ',form

        if(a(1:1).eq.char(12))then
          if(fout)write(2,'(a1,:)')char(12)
          if(.not.fout)print*,'------------FORM FEED------------'
          b=a(2:160)
          a=b
        endif

        b=' '                           !turn tabs to spaces
        j=1
        do i=1,160
          if(a(i:i).eq.char(9))then
            j=(j-1)/8*8+8+1
          elseif(j.le.160)then
            b(j:j)=a(i:i)
            j=j+1
          endif
        enddo

        a=b
        bsave=b
        b=' '
        i1=i3                           !# of nest levels before current line
        i4=0                            !1 to flag start or end of block
        iquote=0                        !no ' yet
        idquote=0                       !no " yet
        icomment2=0                     !anything outside comment?
        icomment3=icomment              !no comment occurred?
        i=1
        j=1
        dowhile(i.le.160.and.j.le.160)  !handle upper case
          c=a(i:i)
          if(c.ge.'A'.and.c.le.'Z')c=char(ichar(c)+32)
          if(c.eq.''''.and.idquote.eq.0.and.icomment.eq.0)then
            iquote=1-iquote
            if(i.gt.1)then
              if(iquote.eq.0.and.a(i-1:i-1).eq.'\')iquote=1-iquote
            endif
          endif
          if(c.eq.'"' .and.iquote .eq.0.and.icomment.eq.0)then
            idquote=1-idquote
            if(i.gt.1)then
              if(idquote.eq.0.and.a(i-1:i-1).eq.'\')idquote=1-idquote
            endif
          endif
          if(c.eq.'/'.and.i.lt.160.and.iquote.eq.0.and.idquote.eq.0)
     &     then
            if(a(i+1:i+1).eq.'*')then
              if(icomment.ne.0)then
                PRINT*,'***WARNING--nested comment line',form
                print*,char(7)
              endif
              icomment=1
              icomment3=1
              c=' '
              a(i+1:i+1)=' '
            endif
          endif
          if(c.eq.'*'.and.i.lt.160.and.iquote.eq.0.and.idquote.eq.0)
     &     then
            if(a(i+1:i+1).eq.'/')then
              if(icomment.eq.0)then
                PRINT*,'***WARNING--*/ without /* clause line',form
                print*,char(7)
              endif
              icomment=0
              c=' '
              a(i+1:i+1)=' '
            endif
          endif
          if(icomment.ne.0)c=' '
          if(c.ne.' ')icomment2=1
          if(c.eq.'{')then
            i3=i3+1
          elseif(c.eq.'}')then
            i3=i3-1
            i4=max(i4,i1-i3)
            if(i3.lt.0)then
              PRINT*,'***ERROR--INVALID DIAGRAMMING INDEX line',
     &         form
              if(fout)
     &         WRITE(2,*)'***ERROR--INVALID DIAGRAMMING INDEX!***'
              print*,char(7)
              i3=max(i3,0)
            endif
          endif
          b(j:j)=c
          if(j.gt.1)then                !(kill multiple spaces)
            if(c.eq.' '.and.a(j-1:j-1).eq.' ')j=j-1
          endif
          j=j+1
          i=i+1
        enddo

        if(ipreproc.ne.0)then
          if(find(b,'#if',2).or.find(b,'# if',2))then
            i3=i3+1
            i4=1
          elseif(find(b,'#else',2).or.find(b,'# else',2)
     &    .or.find(b,'#elif',2).or.find(b,'# elif',2))then
            i4=1
          elseif(find(b,'#endif',2).or.find(b,'# endif',2))then
            i3=i3-1
            i4=1
          endif
        endif
        igoto=0         !no goto on line
        if(find(a,'go to',64+512).or.find(a,'goto',64+512)
     &   .or.find(a,'return',32+512)
     &   .or.find(a,'break',32+512).or.find(a,'continue',32+512)
     &   .or.find(a,'exit',32+512))igoto=1
        if(find(b,'case ',512).or.find(b,'default: ',512))i4=1

20      b=bsave
        a=' '
        if(i1.lt.0.or.i3.lt.0.or.i4.lt.0)then
          PRINT*,'***ERROR--INVALID DIAGRAMMING INDEX line',form
          if(fout)WRITE(2,*)'***ERROR--INVALID DIAGRAMMING INDEX!***'
          print*,char(7)
          i1=max(i1,0)
          i3=max(i3,0)
          i4=max(i4,0)
        endif
        i2=max(i1,i3)                   !# of nests on current line
        jj=max(1,min(16,2*i2-1))
        if(i2.gt.0)a=aa(1:jj)
        i4=max(i4,i3-i1)
        if(i4.ne.0)then
          jjj=1
          dowhile(jjj.lt.160.and.b(jjj:jjj).eq.' ')
            jjj=jjj+1
          enddo
          if(jjj.gt.2)b(1:jjj-2)=
     &     '---------------------------------------------------'
          a(jj:16)='-------------------------------'
          if(jjj.eq.1)a(15:16)=' '
        endif
          do i=0,i4-1
            a(max(1,min(15,jj-i*2)):max(1,min(15,jj+1-i*2)))='+-'
          enddo
        if(iline.ne.0.and.b(max(1,iline):160).eq.' ')then
          if(form(1:1).eq.' ')form(1:1)='|'
          b(iline:iline+4)=form
        endif
        n=160
        dowhile(n.gt.1.and.b(n:n).eq.' ')
          n=n-1
        enddo
        if(icomment2.eq.0.and.icomment3.ne.0..and.
     &   inotate.ne.0)a(13:13)='='
        if(igoto.ne.0)a(13:13)='*'
c last minute change to reduce spaces in diagram block:
        if(fout)write(2,2)(a(i:i),i=1,15,2),(b(i:i),i=1,n)
        if(.not.fout)write(*,2)' ',(a(i:i),i=1,15,2),(b(i:i),i=1,n)
2       format(132a1)
        i1=i3
        goto 10
99      if(iunit.eq.3)then
          iunit=1
          i1=i1-1
          close(3)
          goto 10
        endif
        if(i3.gt.0)then
          PRINT*,'***WARNING--SOME NEST LEVELS LEFT HANGING AT END***'
          print*,char(7)
        endif
        end
c-----------------------------------------------------------------------
        logical function find(a,b,icond) !find b in a, subject to conditions:
                                        !icond=sum of the following:
                                        !2:  Must be first non-blank
                                        !32: Next character not alphanumeric
                                        !64: Next character not alphabetic
                                        !512  Prior character, if present,
                                        !    must be blank or ) or } or { or ;
c Program by Mitchell R Grunes, ATSC/NRL (grunes@nrlvax.nrl.navy.mil).
c Revision date: 5/9/95.
        character*(*) a,b
        character*1   c,cNext
        common icol
        logical result

        ii=len(a)
        jj=len(b)
        result=.false.
        do i=1,ii-jj+1
          if(a(i:i+jj-1).eq.b)then
            icol1=i                     ! icol1=column of item found
            icol =i+jj                  ! icol =colomn after item found

            c=' '
            cNext=' '
            if(icol1.gt.1)c=a(icol1-1:icol1-1)
            if(icol .le.ii)cNext=a(icol:icol)

            result=.true.

            if(result.and.iand(icond,2).ne.0.and.icol1.gt.1)then
              result=a(1:icol1-1).eq.' '
            endif

            if(result.and.iand(icond,32).ne.0)
     &       result=(cNext.lt.'0'.or.cNext.gt.'9').and.
     &              (cNext.lt.'a'.or.cNext.gt.'z')

            if(result.and.iand(icond,64).ne.0)
     &       result=(cNext.lt.'a'.or.cNext.gt.'z')

            if(result.and.iand(icond,512).ne.0)result=c.eq.' '
     &       .or.c.eq.';'.or.c.eq.')'.or.c.eq.'{'.or.c.eq.'}'

            find=result
            if(result)return
          endif
        enddo
        find=result
        return
        end
c-----------------------------------------------------------------------
        function LenA(a)                        ! Length of string, at least 1
c Program by Mitchell R Grunes, ATSC/NRL (grunes@nrlvax.nrl.navy.mil).
c Revision date: 5/9/95.
        character*(*) a
        n=len(a)
        dowhile(n.gt.1.and.a(n:n).eq.' ')
          n=n-1
        enddo
        LenA=n
        end
---diagramc.bat--------------CUT HERE-----------------------------
rem procedure to diagram a C language program,

rem  by Mitchell R Grunes.

rem I assume that the executable is in directory \gsar89\grunes on
rem  your PC.

rem Syntax:
rem     diagramc
rem to be prompted for input parameters.

rem Alternate Syntax:
rem     diagramc filename(s)
rem to append diagram of file(s) into diagram.out

if %1a == a  c:\gsar89\grunes\diagramc
if %1a == a  goto quit

echo off
:loop

  echo ========================-- %1 --========================

  echo %1          >  diagram.sc
  echo diagram2.sc >> diagram.sc
  echo 0           >> diagram.sc
  echo 1           >> diagram.sc
  echo 1           >> diagram.sc
  \gsar89\grunes\diagramc < diagram.sc
  type diagram2.sc >> diagram.out
  del diagram.sc
  del diagram2.sc
  shift
  if not %1a == a goto loop

:quit
-----------------------------CUT HERE-----------------------------

-------------------------------------------------------------------------
  (Opinions are mine alone.)
  Mitchell R Grunes (grunes@nrlvax.nrl.navy.mil)
  Allied-Signal Technical Services


