[comp.lang.fortran] Using cpp for macro substitution.

quinlan@physics.utoronto.ca (Gerald Quinlan) (07/07/90)

I have a question about using the C preprocessor to perform macro
substitutions in a Fortran program.  The problem is the following.  I have
a short subroutine which adds two numbers (a,b) in extended precision,
returning their sum (sum) and the error made in the addition (error).  This
routine gets called about 8 times in a heavily-used do loop in my program,
so I thought I could speed things up by eliminating the subroutine call and
doing the add in-line.  I tried to get the preprocessor cpp to do the
in-line substitution automatically for me, as shown below in the sample
program adtest.F.

--------------------------- adtest.F ----------------------------------
#define CALL_ADD(a,b,sum,error)\
        dum=a+b \
        if(abs(a).gt.abs(b)) then \
          error=a-dum \
          error=error+b \
        else \
          error=b-dum \
          error=error+a \
        endif \
        sum=dum 

      program adtest
      double precision dum,err,resid,rn,sum
      integer n
      sum=0.d0
      resid=0.d0
      do 10 n=1,500000
        rn=sqrt(dble(n))
        CALL_ADD(sum,rn,sum,err)
        resid=resid+err
   10 continue
      sum=sum+resid
      write(6,*) 'addt:',sum,resid
      stop
      end


When I run this through cpp (on a Sun) to get adtest.f I get the result shown
below.

--------------------------- adtest.f ----------------------------------
      program adtest
      double precision dum,err,resid,rn,sum
      integer n
      sum=0.d0
      resid=0.d0
      do 10 n=1,500000
        rn=sqrt(dble(n))
        dum=sum+rn if(abs(sum).gt.abs(rn)) then err=sum-dum err=err+rn else err=rn-dum err=err+sum endif sum=dum
        resid=resid+err
   10 continue
      sum=sum+resid
      write(6,*) 'addt:',sum,resid
      stop
      end


Note how cpp has combined all the statements of the macro into one long line.
I suppose this isn't a problem in C, where the statements end with ";" and
more than one statement per line is allowed.  But in Fortran this doesn't
work; the compiler won't accept adtest.f.  Does anyone know how to get
around this?  I've tried various tricks to get the macro inserted properly,
but can't seem to find anything that works.

worley@compass.com (Dale Worley) (07/09/90)

quinlan@physics.utoronto.ca (Gerald Quinlan) writes:
> I have a question about using the C preprocessor to perform macro
> substitutions in a Fortran program.

> #define CALL_ADD(a,b,sum,error)\
>         dum=a+b \
> [etc.]

> Note how cpp has combined all the statements of the macro into one long line.

There is no way to get around this with CPP.  The problem is that CPP
macro definitions are exactly one line long.  (CPP is line-oriented
like Fortran, despite that C is not!)  The backslashes at the ends of
lines are really escape characters that mean "delete the newline that
follows me".  Since the deletion of the newline is in a (logical)
processing pass before CPP's macro processing, it is impossible to get
one outputed.  Thus, it is impossible to have the output of a macro
span more than one line.

Oddly, a macro *call* is allowed to span more than one line.

Dale Worley		Compass, Inc.			worley@compass.com
--
It is easier to get forgiveness than permission.

ted@hasvcr.UUCP (Ted Powell) (07/11/90)

In article <1990Jul6.162153.17644@helios.physics.utoronto.ca> quinlan@physics.utoronto.ca (Gerald Quinlan) writes:
>I have a question about using the C preprocessor to perform macro
>substitutions in a Fortran program. ...
[example omitted]
>Note how cpp has combined all the statements of the macro into one long line.
>I suppose this isn't a problem in C, where the statements end with ";" and
>more than one statement per line is allowed.  But in Fortran this doesn't
>work; the compiler won't accept adtest.f.  Does anyone know how to get
>around this?  I've tried various tricks to get the macro inserted properly,
>but can't seem to find anything that works.

Your problem is that you want to get characters into the macro expansion
that cpp considers special. An unescaped newline terminates the macro
definition, rather than being included in it, and consecutive spaces
are reduced to a single space.

Pick a couple of characters that do not otherwise occur in your source
files, for example percent to represent newline and underscore to
represent space. Then (assuming you are in a Unix environment; you'll
have to use an intermediate file otherwise) pipe the output of cpp
through:
		tr '_%' ' \012'
			 ^note space

This translates underscores into spaces and percent signs into newlines
(\012 is interpreted by tr as a newline character). Note that some
versions of the tr program require their arguments in a slightly
different form--check your manual if necessary.

Your macros now look something like:
	#define qqsv(a,b,c) line one\
	%______line two\
	%______line three\
	%______last line
	^column 1

The remainder of your program is of course unchanged, since actual
spaces and newlines are unaffected by their trip through tr.

All this takes much less time to do than to describe, of course.

M4 is a nice language. I used a similar language called UMIST heavily
for many years as a Fortran preprocessor, and as an MVTAB (multivariate
contingency tabulator) preprocessor. But in your circumstances I think
M4 is overkill.

-- 
ted@hasvcr.wimsey.bc.ca   ...!ubc-cs!van-bc!hasvcr!ted    (Ted Powell)