PS
#CanLogic
ifdef(`L_unit',,`include(liblog.m4)')
log_init(svg_font(sans-serif,11bp__))

divert(-1)
###########################################################################
                               Macros for automatically drawing 2-layer
                               Boolean functions

                               Style parameters
define(`dotrad_',(0.01*scale))
define(`gatelineth',1)
define(`lineth',0.5)
define(`inputsep',`2*jog')
define(`jog',`(AND_ht/2)*L_unit')

                              `CanLogic(layer gate type,[N],
                                        output gate type,[N],
                                        term,term,...)
                               This is the driver macro.  Terms are
                               strings of variables or of variables
                               preceded by the ~ character. Each
                               variable is one letter e.g.
                               CanLogic(NAND,,OR,N,abcd,a~b,c,~ad)'
define(`CanLogic',
`define(`terms',`shift(shift(shift(shift($@))))')
#                               Determine required input variables and negated
#                               variables
 Loopover_(`t_',`CLvarloop(`v_',`define(X`'v_)',`define(XN`'v_)',t_)',terms)
#                               Draw the inputs with NOT gates as necessary
 LastInput: Here-(inputsep,0)
 Loopover_(`t_',`CLvarloop(`v_',
  `ifdef(D`'v_,,`ifdef(XN`'v_,`CLDrawInNotIn(v_)',`CLDrawIn(v_)')')',
  `ifdef(D`'v_,,`ifdef(X`'v_,`CLDrawInNotIn(v_)',`CLDrawNotIn(v_)')')', t_)',
  terms)
#                               Draw 2nd-layer gates
 right_
 LastGateSE: LastInput+(5*jog,-(AND_wd*L_unit*1.5))
 Loopover_(`t_',
  `define(`termcount',m4Lx)CLDrawLayerGate(G`'termcount,$1,$2,t_)',
   terms)
#                               Draw output gate
 linethick = gatelineth
 OP: m4xpand(`$3'_gate(termcount,$4)) with .Out at \
   0.5<G1.Out,G`'termcount.Out> + (jog/2*(termcount+3)+AND_wd*L_unit,0)
 Out: Here
 linethick = lineth
#                               Connect 2nd-layer gates to the output gate
 CLVectorConnect(G,termcount,OP)
#                               Connect the inputs and negated inputs to
#                               2nd-layer gates
 Loopover_(`t_',`CLConnectInputs(G`'m4Lx,t_)',terms)
#                               Clean up
 Loopover_(`t_',`CLDeleteLogDefs(t_)',terms)
')
                              `CLVectorConnect(number of 2nd layer gates,
                                             common 2nd layer gate name,
                                             output gate name)
                               Connect the 2nd-layer gate outputs to the
                               output gate inputs'
define(`CLVectorConnect',
`for_(1,`$2',1,
 `line from `$1'm4x.Out right `$3'.In1.x-`$1'm4x.Out.x \
   - jog/2*(`$2'+1-abs(2*m4x-`$2'-1)) \
   then down `$1'm4x.Out.y - `$3'.In`'m4x.y then to `$3'.In`'m4x ')')

                               Draw and label a non-inverted input
define(`CLDrawIn',
`LastInput: LastInput+(inputsep,0)
 In`'$1: LastInput
 "svg_it($1)" ljust at LastInput     # Maybe labels should be done externally
 Int`'$1: LastInput
 define(D`'$1)')

                               Draw and label an inverted input
define(`CLDrawNotIn',
`LastInput: LastInput+(inputsep,0)
 InN`'$1: LastInput
 "svg_it($1)" ljust at LastInput     # Maybe labels should be done externally
 line down_ 2*jog from LastInput
 linethick = gatelineth
 NOT_gate
 InNt`'$1: Here
 linethick = lineth
 define(D`'$1)')
                               Draw and label an input that is required both
                               inverted and uninverted.
define(`CLDrawInNotIn',
`LastInput: LastInput+(inputsep,0)
 In`'$1: LastInput
 "svg_it($1)" ljust at LastInput     # Maybe labels should be done externally
 line from LastInput down jog
 Int`'$1: dot
 LastInput: LastInput+(inputsep,0)
 line to (LastInput,Here) then down_ jog
 linethick = gatelineth
 NOT_gate
 linethick = lineth
 InNt`'$1: Here
 define(D`'$1)')
                              `CLvarloop(`var',ifnotnegated,ifnegated,term)
                               Loop over term variables performing actions'
define(`CLvarloop',`ifelse(`$4',,,substr(`$4',0,1),~,
  `define(`$1',substr($4,1,1)) $3
   CLvarloop(`$1',`$2',`$3',substr($4,2))',
  `define(`$1',substr($4,0,1)) $2
   CLvarloop(`$1',`$2',`$3',substr($4,1))')')')

                               Count gate inputs and mark last appearance
define(`CLCountinputs',`CLvarloop(`v_',
`define(`incount',incr(incount)) define(Last`'v_,`$1')',
`define(`incount',incr(incount)) define(LastN`'v_,`$1')',$2)')

                               Draw a 2nd layer gate
define(`CLDrawLayerGate',
`define(`incount',0)
 CLCountinputs($1,$4)
 ifelse(incount,1,
  `LastGateSE: LastGateSE-(0,jog)
   $1: [ In1:Here; line right AND_wd*L_unit; Out: Here] \
    with .Out at LastGateSE',
  `LastGateSE: LastGateSE-(0,jog+AND_ht*L_unit)
   linethick = gatelineth
   $1: m4xpand(`$2'_gate(incount,$3)) with .se at LastGateSE
   linethick = lineth ')')

                               Connect this gate to its input lines
define(`CLConnectInputs',`define(`innum',0) CLvarloop(`v_',
`define(`innum',incr(innum))
 line from `$1'.In`'innum to (In`'v_,`$1'.In`'innum)dnl
   ifelse(`$1',m4xpand(Last`'v_),`then to In`'v_',`; dot')',
`define(`innum',incr(innum))
 line from `$1'.In`'innum to (InNt`'v_,`$1'.In`'innum)dnl
   ifelse(`$1',m4xpand(LastN`'v_), `then to InNt`'v_', `; dot')',$2)')

                               Delete definitions to allow more than one
                               circuit per diagram
define(`CLDeleteLogDefs',`CLvarloop(`v_',
  `undefine(Last`'v_) undefine(D`'v_) undefine(X`'v_)',
  `undefine(LastN`'v_) undefine(D`'v_) undefine(XN`'v_)',$1)')

                               Thanks to Alexander Ray for suggesting the
                               need for something like these macros
###########################################################################
divert(0)dnl

 linethick = lineth

[ CanLogic(AND,,OR,,abcd,a~b,c,~ad) #; line right jog from Out "svg_it(f)" above
 ]
{`"CanLogic(AND,,OR,,abcd,a~b,c,~ad)"' at last [].s -(0,11bp__)}

[ CanLogic(OR,N,NAND,,ab~c,a~bc,ac,~d) #; line right jog from Out "$f$" above
 ] with .sw at last [].se+(0.5,0)
{`"CanLogic(OR,N,NAND,,ab~c,a~bc,ac,~d)"' at last [].s - (0,11bp__)}

command "</g>" # end font
PE