On 01/13/2012 06:49 PM, jfw wrote: > > Am I correct in assuming that the following is doable using M4.
M4 is a Turing complete language, so without reading your question, I can state that yes, it should be possible. That said, the devil's in the details :) > If so are there M4 implementations of macros available on the web to do this > sort of thing > that I can model my m4_lib.m4 code on? That, I don't know. autoconf has a pretty good library of m4 macros, but they are tuned more to shell script generation. > Here's what I'm trying to do: > use a library of M4 macros: m4_lib.m4 > use text files {g,h,s}.txt containing general definition of items > use specific M4 files: {e,g,h,s}_{enum,name,hash}.m4 to generate files from > the txt files. > generate .h files: {e,g,h,s}_enum.h, {g,h)_name.h, and s_hash.h. > > macros: > > __in(name,value,flags,comment) definition selected from m4_lib.m4 by flag > settings Considering just __in(), I would lay things out so that m4_lib.m4 has common setup, then specific .m4 files have the appropriate definitions for the end result file it will be generating. Going by your example, that means for converting .txt to enum, you would have enum.m4 contain: define(`__in', `\tg_$1\t=\t$2,\t$4')dnl while for converting .txt to name, you would have name.m4 contain: define(`__in', `\t"$1",')dnl Then to run the conversions, you would do: m4 m4_lib.m4 enum.m4 g.txt > g_enum.h m4 m4_lib.m4 enum.m4 h.txt > h_enum.h m4 m4_lib.m4 name.m4 g.txt > g_name.h m4 m4_lib.m4 name.m4 h.txt > h_name.h Or are you trying to say that __in() should probe the third argument to decide whether to make an output or skip a line, according to the flags present in that argument? In that case, I'd suggest you put this in m4_lib.m4: define(`__ENUM', `1')dnl define(`__NAME', `2')dnl then in enum.m4: define(`__in', `ifelse(expr((($3) & __ENUM) == __ENUM), `1', `\tg_$1\t=\t$2,\t$4')')dnl and in name.m4: define(`__in', `ifelse(expr((($3) & __NAME) == __NAME), `1', `\t"$1",')')dnl You didn't quite show what you wanted s_hash to contain, so it's hard to say how to write those macros. > __begbit(initial bit value for __nextbit) This could live in m4_lib.m4, something like: define(`__begbit', `define(`__bit', `$1')')dnl > __nextbit(return 32bit hex representation of value; increase value*2) define(`__nextbit', `__bit`'define(`__bit', format(`0x%x', expr(__bit * 2)))')dnl > __genbit(named base, begin value (default to last __nextbit),end value) Here, you're asking for a tough one. The way you described __begbit, you plan on passing in the power of 2, which means you have to compute the log base 2 of __bit; which is doable using bit-wise manipulations in expr() but not trivial. I'd suggest that you instead rewrite your .txt files to pass in the exponent instead of the power of 2, at which point you then rewrite __nextbit to compute the power of 2. That is, the sequence __begbit(3) __nextbit __nextbit would generate 0x00000008 then 0x00000010, with this definition of __nextbit: define(`__nextbit', `format(`0x%08x', expr(1<<__bit))`'define(`__bit', incr(__bit))')dnl At which point, your desired implementation of __genbit is based on using a for loop, as documented in the m4 manual, in your m4_lib.m4: https://www.gnu.org/software/m4/manual/m4.html#Forloop define(`forloop', `pushdef(`$1', `$2')_forloop($@)popdef(`$1')')dnl define(`_forloop', `$4`'ifelse($1, `$3', `', `define(`$1', incr($1))$0($@)')')dnl define(`__genbit', `forloop(`__i', ifelse(`$2', `', __bit, `$2'), `$3', `\t"$1`'__i", ')dnl')dnl -- Eric Blake ebl...@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
signature.asc
Description: OpenPGP digital signature