#! /bin/sh
#-------------------------------------------------------------------------------
#
#  NAME
#       m5, m5.awk - macro processor
#
#  SYNOPSIS
#       m5 [ -Dname ] [ -Dname=def ] [-c] [ -dp char ] [ -o file ] [
#       -sp char ] [ file ... ]
#
#       [g|n]awk -f m5.awk X [ -Dname ] [ -Dname=def ]  [-c]  [  -dp
#       char ] [ -o file ] [ -sp char ] [ file ... ]
#
#  DESCRIPTION
#       m5 is a Bourne shell script for invoking m5.awk.  m5.awk  is
#       the  m5 macro processor translator.  Its input may be either
#       standard input or one or more files listed  on  the  command
#       line  after  the optional arguments.  An input line with the
#       directive prefix character (# by default)  in  column  1  is
#       termed  a  directive line (or just a directive); such a line
#       is treated as a statement in the  macro  processor  language
#       (awk).   Any other input line is termed a text line.  Macros
#       are defined using awk assignment statements and their values
#       substituted  using  the  substitution prefix character ($ by
#       default).  The backslash (\) is the  escape  character;  its
#       presence  forces  the  next character to literally appear in
#       the output.  This is most useful when forcing the appearance
#       of  the  directive prefix character, the substitution prefix
#       character, and the escape character itself.
#
#       As noted in the synopsis above, its invocation  may  require
#       specification  of  awk, gawk, or nawk, depending on the ver-
#       sion of awk  available  on  your  system.   This  choice  is
#       further  complicated  on  some systems, e.g. Sun, which have
#       both awk (original awk) and nawk (new awk).   Other  systems
#       appear to have new awk, but have named it just awk.  New awk
#       should be used, regardless of what it has been  named.   The
#       macro  processor translator will not work using original awk
#       because the former, for example, uses the built-in  function
#       match().
#
#  OPTIONS
#       The following options are supported:
#
#       -Dname        Following the cpp convention, define name as 1
#                     (one).   This  is  the  same  as if a -Dname=1
#                     appeared as an option or #name=1  appeared  as
#                     an  input  line.  Names specified using -D are
#                     awk variables  defined  just  before  main  is
#                     invoked.
#
#       -Dname=def    Define name as "def".  This is the same as  if
#                     #name="def"  appeared  as an input line. Names
#                     specified using -D are awk  variables  defined
#                     just before main is invoked.
#
#       X             Yes, that really is a capital "X".   The  ver-
#                     sion  of  nawk on Sun Solaris 2.5.1 apparently
#                     does its own argument processing before  pass-
#                     ing  the  arguments on to the awk program.  In
#                     this case, X (and all succeeding options)  are
#                     believed  by  nawk  to  be  file names and are
#                     passed on to the  macro  processor  translator
#                     (m5.awk)  for  its  own  argument processing).
#                     Without the X, Sun nawk  attempts  to  process
#                     succeeding  options  (e.g.,  -Dname)  as valid
#                     nawk  arguments  or  files,  thus  causing  an
#                     error.   This  may  not  be  a problem for all
#                     awks.
#
#       -c            Compile only.  The  output  program  is  still
#                     produced, but the final output is not.
#
#       -dp char      The directive prefix character (default is #).
#
#       -o file       The output program file (default is a.awk).
#
#       -sp char      The substitution prefix character (default  is
#                     $).
#
#  USAGE
#    Macro Substitution
#       All input lines are scanned for macro references  which  are
#       indicated   by  the  substitution  prefix  character  ($  by
#       default).  Assuming this default, macro references may be of
#       the  form  $var,  $(var),  $(expr),  $[str],  $var[expr], or
#       $func(args).  These are replaced by  an  awk  variable,  awk
#       variable, awk expression, awk array reference to the special
#       array M[], regular awk  array  reference,  or  awk  function
#       call,  respectively.   These  are,  in  effect, macros.  The
#       macro processor translator  checks  for  proper  nesting  of
#       parentheses  and  double quotes when translating $(expr) and
#       $func(args) macros, and checks for proper nesting of  square
#       brackets  and  double  quotes  when  translating $[expr] and
#       $var[expr] macros.  The substitution prefix character  indi-
#       cates  a  a  macro reference unless it is (1) escaped (e.g.,
#       \$abc), (2) followed by a character other than A-Z, a-z,  (,
#       or  [  (e.g.,  $@),  or  (3) inside a macro reference (e.g.,
#       $($abc); probably an error).  Consequently, macro references
#       are significant even inside single or double quoted strings.
#       Some examples of macro substitution are given below.
#
#    Macros Containing Macros
#       As already noted, a macro  reference  inside  another  macro
#       reference  will not result in substitution and will probably
#       cause an awk execution-time error.  Furthermore, a substitu-
#       tion prefix character in the substituted string is also gen-
#       erally not significant because the substitution prefix char-
#       acter  is detected at translation time, and macro values are
#       assigned at run time.  However, macro references of the form
#       $[expr] provide a simple nested referencing capability.  For
#       example, if $[abc] is in a text line, or in a directive line
#       and not on the left hand side of an assignment statement, it
#       is replaced by eval(M["abc"]).  When the output output  pro-
#       gram  is executed, the m5 runtime routine eval() substitutes
#       the string M["abc"] examining it for  further  macro  refer-
#       ences  of  the form $[str] (where "str" denotes an arbitrary
#       string).  If one is found, substitution and scanning proceed
#       recursively.   Also note that function type macro references
#       may contain references to other functions, thus also provid-
#       ing a type of nested referencing.
#
#    Directive Lines
#       Except for the include directive, when a directive  line  is
#       detected,  the  directive  prefix  is  removed,  the line is
#       scanned for macros, and then the line is copied to the  out-
#       put  program (as distinct from the final output).  Any valid
#       awk construct, including the function statement, is  allowed
#       in a directive line.
#
#    Include Directive
#       A single non-awk directive has been  provided:  the  include
#       directive.   Assuming  that  "#"  is  the  directive prefix,
#       #include(filename) directs the macro processor translator to
#       immediately  read  from the indicated file, processing lines
#       from it in the normal manner.  Nested includes are  allowed.
#       Include  directives  must  appear  on  a line by themselves.
#       More elaborate types of file processing may be directly pro-
#       grammed using the macro processor language.
#
#    Main Program and Functions
#       The macro processor translator builds the resulting awk pro-
#       gram  in one of two ways, depending on the form of the first
#       input line.  If that line  begins  with  "function",  it  is
#       assumed  that  the  user is providing one or more functions,
#       including the function "main" required by m5.  If the  first
#       line  does  not begin with "function", then the entire input
#       file is translated into  awk  statements  which  are  placed
#       inside  function main.  If some input lines are inside func-
#       tions, and others are not, awk will  will  detect  this  and
#       complain.  Generally, the macro processor by design has lit-
#       tle awareness of the syntax of directive lines  (awk  state-
#       ments).   As a consequence, syntax errors in directive lines
#       are not detected until the output program is executed.
#
#    Text Lines
#       When a text line is encountered, it is scanned  for  macros,
#       embedded  in  awk print statements, and copied to the output
#       program.  For example, the input line
#
#          The quick brown $fox jumped over the lazy $dog.
#
#       is transformed into
#
#          print "The quick brown " fox " jumped over the lazy " dog
#       "."
#
#       Obviously the use of this technique relies completely on the
#       presence  of  the  awk  concatenation  operator  (1  or more
#       blanks).
#
#    Output
#       Finally, unless the -c (compile only) option  is  specified,
#       the  output  program is executed to produce the final output
#       (directed by default to standard output).   The  version  of
#       awk  specified in ARGV[0] (the command name) is used to exe-
#       cute the program.  If ARGV[0] is null, awk is used.
#
#  EXAMPLE
#       Understanding this example requires recognition  that  macro
#       substitution  is  a two-step process:  (i) the input text is
#       translated into an output awk program, and (ii) the awk pro-
#       gram  is executed to produce the final output with the macro
#       substitutions actually  accomplished.   The  examples  below
#       illustrate  this  process.   #  and  $ are assumed to be the
#       directive and substitution prefix characters.
#
#    Input Text
#       #function main() {
#
#          Example 1: Simple Substitution
#          ------------------------------
#       #  br = "brown"
#          The quick $br fox.
#
#          Example 2: Substitution inside a String
#          ---------------------------------------
#       #  r = "row"
#          The quick b$(r)n fox.
#
#          Example 3: Expression Substitution
#          ----------------------------------
#       #  a = 4
#       #  b = 3
#          The quick $(2*a + b) foxes.
#
#          Example 4: Macros References inside a Macro
#          -------------------------------------------
#       #  $[fox] = "\$[q] \$[b] \$[f]"
#       #  $[q] = "quick"
#       #  $[b] = "brown"
#       #  $[f] = "fox"
#          The $[fox].
#
#          Example 5: Array Reference Substitution
#          ---------------------------------------
#       #  x[7] = "brown"
#       #  b = 3
#          The quick $x[2*b+1] fox.
#
#          Example 6: Function Reference Substitution
#          ------------------------------------------
#          The quick $color(1,2) fox.
#
#          Example 7: Substitution of Special Characters
#          ---------------------------------------------
#       \#  The \$ quick \\ brown $# fox. $$
#       #}
#       #include(testincl.m5)
#
#    Included File testincl.m5
#       #function color(i,j) {
#          The lazy dog.
#       #  if (i == j)
#       #     return "blue"
#       #  else
#       #     return "brown"
#       #}
#
#    Output Program
#       function main() {
#          print
#          print "   Example 1: Simple Substitution"
#          print "   ------------------------------"
#          br = "brown"
#          print "   The quick " br " fox."
#          print
#          print "   Example 2: Substitution inside a String"
#          print "   ---------------------------------------"
#          r = "row"
#          print "   The quick b" r "n fox."
#          print
#          print "   Example 3: Expression Substitution"
#          print "   ----------------------------------"
#          a = 4
#          b = 3
#          print "   The quick " 2*a + b " foxes."
#          print
#          print "   Example 4: Macros References inside a Macro"
#          print "   -------------------------------------------"
#          M["fox"] = "$[q] $[b] $[f]"
#          M["q"] = "quick"
#          M["b"] = "brown"
#          M["f"] = "fox"
#          print "   The " eval(M["fox"]) "."
#          print
#          print "   Example 5: Array Reference Substitution"
#          print "   ---------------------------------------"
#          x[7] = "brown"
#          b = 3
#          print "   The quick " x[2*b+1] " fox."
#          print
#          print "   Example 6: Function Reference Substitution"
#          print "   ------------------------------------------"
#          print "   The quick " color(1,2) " fox."
#          print
#          print "   Example 7: Substitution of Special Characters"
#          print "   ---------------------------------------------"
#          print "\#  The \$ quick \\ brown $# fox. $$"
#       }
#       function color(i,j) {
#          print "   The lazy dog."
#          if (i == j)
#             return "blue"
#          else
#             return "brown"
#       }
#
#       function eval(inp   ,isplb,irb,out,name) {
#
#          splb = SP "["
#          out = ""
#
#          while( isplb = index(inp, splb) ) {
#             irb = index(inp, "]")
#             if ( irb == 0 ) {
#                out = out substr(inp,1,isplb+1)
#                inp = substr( inp, isplb+2 )
#             } else {
#                name = substr( inp, isplb+2, irb-isplb-2 )
#                sub( /^ +/, "", name )
#                sub( / +$/, "", name )
#                out = out substr(inp,1,isplb-1) eval(M[name])
#                inp = substr( inp, irb+1 )
#             }
#          }
#
#          out = out inp
#
#          return out
#       }
#       BEGIN {
#          SP = "$"
#          main()
#          exit
#       }
#
#    Final Output
#
#          Example 1: Simple Substitution
#          ------------------------------
#          The quick brown fox.
#
#          Example 2: Substitution inside a String
#          ---------------------------------------
#          The quick brown fox.
#
#          Example 3: Expression Substitution
#          ----------------------------------
#          The quick 11 foxes.
#
#          Example 4: Macros References inside a Macro
#          -------------------------------------------
#          The quick brown fox.
#
#          Example 5: Array Reference Substitution
#          ---------------------------------------
#          The quick brown fox.
#
#          Example 6: Function Reference Substitution
#          ------------------------------------------
#          The lazy dog.
#          The quick brown fox.
#
#          Example 7: Substitution of Special Characters
#          ---------------------------------------------
#       #  The $ quick \ brown $# fox. $$
#
#  FILE
#       a.awk         default output program file
#
#  SEE ALSO
#       awk(1), cpp(1), gawk(1), m4(1), nawk(1).  vi(1)
#
#  AUTHOR
#       William A. Ward, Jr., School  of  Computer  and  Information
#       Sciences, University of South Alabama, Mobile, Alabama, July
#       23, 1999.
#
#-------------------------------------------------------------------------------

#AWK=awk
#AWK=gawk
AWK=nawk
$AWK -f $0.awk X $*
