muparkkra / mup

Mup music publication program
Other
9 stars 2 forks source link

make duplicate parameter names in macros work like most other preprocessors #699

Open muparkkra opened 5 years ago

muparkkra commented 5 years ago

Given the following input file:

    define X(ASTR) helvetica rom (10) analysis ASTR ; @ 
    define S_BS 6 @ 
    define XBS(ASTR) X(below S_BS: ASTR) @ 
    XBS( this is text ) 

I would expect mup -E -C to produce

    helvetica rom (10) analysis below 6: this is text  ; 

But it actually produces

    helvetica rom (10) analysis  this is text  ; 

I didn't see anything in the documentation that would lead me to expect this, and I think it's a bug.

muparkkra commented 5 years ago

Mail exchange about the issue:

The issue is that macro X is being passed ASTR in its arguments, but its own argument name is also ASTR, so there is some ambiguity on the meaning of ASTR. If you change the first line from define X(ASTR) helvetica rom (10) analysis ASTR ; @ to define X(ASTRING) helvetica rom (10) analysis ASTRING ; @ so the names differ, then it works as you expected.


As it happens, there is a big literature on macro-processing systems dating back at least to the 1960s, with some of which I am familiar from having worked on such systems as a developer, and the literature is unanimous that the above behavior is a bug. I agree. The problem is that with the above interpretation, the caller of a macro must know the names of the parameters of that macro (and of all macros it calls), and avoid them in the parameters passed to the macro. For the caller of a macro to know the implementation details of a set of macros that may have been written by someone else, and whose membership may be onerous to determine, is considered an unreasonable burden.

I suspect that mup scans the macro definition for occurrences of the argument name as the macro is being expanded, inserts arguments in the expanded stream literally, and then scans the inserted arguments in the same way as the definition body. It is the combination of these things that causes the problem.

There are a number of ways of fixing this. Probably the simplest is to turn off recognition of argument names when scanning text originating from an argument. This does require a little more bookkeepping during macro expansion. A more typical approach is to scan the macro definition at defining time rather than at calling time, recognizing argument names and replacing them with some kind of special marks that cannot occur in the real input stream.

I realize that from your point of view this is a pretty arcane point, and I would understand completely if you decided not to fix the problem. If that is your choice, I suggest noting in the documentation that this is an issue.