URI:
       # 2026-01-04 - M1 Macro Processor Retreat
       
       I wrote a prototype gopher front-end to the Internet Archive [1].  It
       was a single file AWK script using CGI.  In some ways it was elegant,
       but i received feedback that it should be broken into smaller files.
       
       GNU AWK has an include() function, but i wasn't using gawk.  So i
       implemented include() using m4, which will work with any AWK.  I
       wrote macros portable to both BSD and GNU m4.  It seemed like a
       reasonable combination because AWK and m4 are both part of POSIX.
       
       Macro processors have been called a rite of passage for programmers
       since the beginning of time.  I've spent a lot of time debugging
       GNU autoconf scripts.  Don't get me started on automake and libtool.
       The proliferation of new build systems takes it way past
       "rite of passage" material.  Now it's more like a gauntlet.  In
       contrast, imake and xmkmf look like child's play.
       
       Child's play is what i like about minimal software.  Toys are fun.
       Code i can wrap my mind around in a single lazy Sunday afternoon.  So
       i was delighted to discover another antique: the m1 macro processor.
       If m4 is the advanced stage, then m1 isn't even larval yet.  m1 is
       more of a retreat than a rite of passage.
       
       What a coincidence, the author used m1 [2] [3] to create a module
       system for AWK, just as i had done with m4!  m1 was written in just a
       little over 100 lines of AWK code.  I found a version extended by
       Dave Bucklin to support RPN math expressions.
       
       Just for fun i wrote expr.m1 [5], a small macro to do infix math
       expressions.  I didn't need to change m1.awk.  Behind the scenes it
       uses the @shell macro to evaluate each expression through an AWK
       child process.
       
       Here is an example:
       
           $ cat >test1.txt <<__EOF__
           @include expr.m1
           @define cols 24
           @define rows 80
           @expr@ cells @(@ @cols@ * @rows@ @)@
           Cells = @cells@
           __EOF__
           
           $ awk -f m1.awk test1.txt
           Cells = 1920
       
       While reading about macro processors, i found ML/I [6].  It can often
       transform its own source code to a host assembler or compiler.  I
       imagine it's possible to implement m1 using ML/I, but i suspect it
       would take two passes.  Scanning the documentation i don't see how
       ML/I could implement the @include macro without a helper program.
       
       Bailing wire and duct tape are classics; they never get old.  :)
       
       tags: retrocomputing,technical
       
       # Footnotes
       
   DIR [1] PHAROS
       
  TEXT [2] m1.awk
       
  TEXT [3] M1 article
       
  TEXT [5] expr.m1
       
  TEXT [6] ML/I
       
  TEXT [7] Using the m4 macro processor for fun and profit
       
   BIN [8] Exploiting the m4 macro language by Kenneth J. Turner (PDF)
       
  TEXT [9] M4 complete guide by Jerry Peek
       
  TEXT [10] M4 quoting tips
       
  TEXT [11] Notes on the M4 Macro Language by Michael Breen
       
       # Tags
       
   DIR retrocomputing
   DIR technical