Writing an M4 recursive macro for dotgraph notation

122 Views Asked by At

I'm trying to write an M4 macro to produce dotgraph notation but I'm struggling with the recursion.

I would like to have a macro which takes the first parameter, and adds the dotgraph relation for all the remaining parameters. For example

coachExisting(a, b, c, d)

would produce

a -> b; a -> c; a -> d;

This was my attempt at it:

define(coachExisting, `ifelse(eval($#==2), 1, `ifdef(first, first, $1) -> $2;',
ifelse(eval($#>2), 1,
`ifdef(first, ,define(first, $1)) first -> $2; $0(shift($*))')
)')

However this only seems to work if I use numbers

coachExisting(1, 2, 3, 4)
1 -> 2;  1 -> 3; 1 -> 4;

When I try with letters, it seems to lose the first definition.

coachExisting(a, b, c, d)
b -> b;  b -> c; c -> d;
1

There are 1 best solutions below

0
markasoftware On

You are playing fast and loose with quoting. Please read the m4 manual carefully for guidance about quoting and recursive macro evaluation. On the first expansion, you get define(first, $1) => define(first, a). But on the second execution, it expands as define(first, $1) => define(first, b) => define(a, b) (because the first is expanded as a macro). You need to quote the first everywhere you can, so define(`first', `$1')', for starters.

A much cleaner way to implement your macro is to avoid a temporary macro to begin with. I'd recommend something like:

define(`coachExisting', `ifelse(eval($#==2), 1,
    `$1 -> $2',
    `$1 -> $2; $0(`$1', shift(shift($@)))')')

(be careful though -- I haven't designed this macro to handle the cases with 0 or 1 argument).