Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!uunet!aspect!dave From: dave@aspect.UUCP (Dave Corcoran) Newsgroups: comp.lang.c Subject: Re: Macros with multi-line results? Summary: possible m4/perl solution Message-ID: <7402@aspect.UUCP> Date: 22 Jan 91 21:35:21 GMT References: <16101@burdvax.PRC.Unisys.COM> Organization: Aspect Telecommunications, San Jose, Ca Lines: 185 In article <16101@burdvax.PRC.Unisys.COM>, fritzson@PRC.Unisys.COM (Richard Fritzson) writes: > I am trying to write a macro which generates more than one line of > output. > > as output from the C preprocessor. I would very much like to get > > body > more body > still more > > somehow. Is this possible? > Here is an m4 solution, named perldef (in perlmac.m) using perl. The macro which follows will define another macro which can be invoked inline (via m4 (SunOS users use /usr/5bin/m4)) and can use any perl script. Quoted constructs: '\'' to insert tics \\n to insert \n %% to insert % so the string " '\''%%s'\''\\n " yields " '%s'\n " in the output perl *script*. Options to perl can be passed as $3 of the definition. The contents of perlmac.m follows ---------------------8<-------------------------- define(perldef, `syscmd((echo ' '$2' | sed 's/^(//;s/^)//' `>/tmp/pm_$1))' `define($1,`syscmd(perl $3 /tmp/pm_$1 $'`1 ifelse($'`2,,,<<@@ $'`2 @@))')' ) ---------------------8<-------------------------- Two forms of invocation can be used: (where xx is the macro definition) 1. xx([arg1 ... argN]) This form places arg1 -> argN in arg list (i.e. @ARGV). Note the *absence* of *any* commas in the arg list. 2. xx(,arg1.1 arg1.2 arg2 arg3 arg4 arg4.1) This presents the arg list as the "here-is" form. i.e. perl scriptfilename <<@@ arg1 arg1.1 arg1.2 arg2 arg3 arg4 arg4.1 @@ Note the usage of the leading comma and absence of any commas in the balence of the list. An example of how to use follows: (tst.c.m) (^^^^ -- is this an ok convention?) Note that the placement of the 2nd inner parens, which allows commas to be used in the script, must be the first and last characters in the macro; the perldef macro strips them out using: sed 's/^(/^)/' so all lines with leading parens column 1 will be deleted. This is a bug(feature). tst.c.m ---------------------8<-------------------------- include(perlmac.m) perldef(xx,( for $i (@ARGV) { printf qq/#define %s %d\n/,$i,++$j; } )) perldef(yy,( for $i (@ARGV) { @l=split(/ */,$i); @l[0]=~y/a-z/A-Z/; $m=join("",@l); $i=~y/a-z/A-Z/; printf qq/#define %s "%s"\n/,$i,$m; } )) perldef(zz,( for $i (@ARGV) { $j=$i; $i=~y/a-z/A-Z/; printf qq/ printf("-- %%d -- %%s\\n",$j,$i);\n/; } print qq/ printf("'\''this is in single quotes'\''\\n");\n/; ## note that $HOME contains "/" so qq/ will not work print qq@ printf("this is my current dir - ' $HOME '\\n");\n@; )) define(`vars',one two three four five six) define(`vars',vars seven eight nine ten eleven) xx(vars) yy(vars) main() { zz(vars) } ---------------------8<-------------------------- m4 tst.c.m >tst.c Invocation given the above yields: (leading blank lines deleted) #define one 1 #define two 2 #define three 3 #define four 4 #define five 5 #define six 6 #define seven 7 #define eight 8 #define nine 9 #define ten 10 #define eleven 11 #define ONE "One" #define TWO "Two" #define THREE "Three" #define FOUR "Four" #define FIVE "Five" #define SIX "Six" #define SEVEN "Seven" #define EIGHT "Eight" #define NINE "Nine" #define TEN "Ten" #define ELEVEN "Eleven" main() { printf("-- %d -- %s\n",one,ONE); printf("-- %d -- %s\n",two,TWO); printf("-- %d -- %s\n",three,THREE); printf("-- %d -- %s\n",four,FOUR); printf("-- %d -- %s\n",five,FIVE); printf("-- %d -- %s\n",six,SIX); printf("-- %d -- %s\n",seven,SEVEN); printf("-- %d -- %s\n",eight,EIGHT); printf("-- %d -- %s\n",nine,NINE); printf("-- %d -- %s\n",ten,TEN); printf("-- %d -- %s\n",eleven,ELEVEN); printf("'this is in single quotes'\n"); printf("this is my current dir - /home/dave \n"); } -- David Corcoran -@@ uunet!aspect!dave ~ In a society where anything goes eventually everything will.