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