Quote:
An incomplete macro definition is not visible.
Take care to ensure that recursive macros are still possible. It sounds like it might be, but it should be an explicit requirement.
Quote:
Should the macro engine be aware of anything beyond text expansion? Should it know about lines, or fields within a line? I hope not.
You need to ensure that at least line numbers will be retained throughout the pipeline for good error reporting. This means that the output of a macro system is not just expanded text, but requires annotations somehow to note what file & line number the bits came from.
If you really look at it, every assembler's macro & state system really wants to be a full programming language, managing assemble-time variables for anything from building labels & tables to full on code generation. Being able to generate code from code is the all-encompassing ideal; any deviation from that is making hopeful tradeoffs. If you're serious about a macro system that will not be constrained, and you're looking at starting to use different tools anyway, Lisp is king in that field. Python borrows a fair amount from Lisp, so it shouldn't be too foreign.
While there are very few tools around for general Lisp-based assemblers, here's a snippet I found via google:
linkQuote:
In 1983, Rescue on Fractalus and Ballblazer, the first releases from Lucasfilm Games, were built with a system written in Lisp. It was a 6502 assembler with Lisp syntax and a Lisp-style macro facility, written in Portable Standard Lisp, running in Berkeley Unix on a 4MB VAX 11/750. Unfortunately it was eventually abandoned because the developer had left and it was a bit of a strain on the VAX that was shared by the whole development team.
Yes, I wrote it. Yes, it was my first non-academic programming job. Yes, the users complained about the parentheses, and the slowness. But, they also took advantage of the powerful macro facility.
(Of course, Lisp implementations are generally native-speed compilers nowadays.)
This page is quite technical, but writes a macro assembler in Lisp targeting the NES. While some of the main code looks like fairly straight 6502 code, the music for the demo ends up looking like this:
Code:
(four-on-the-floor ()
(repeat 4 (thump 32 (et -24))))
(intro-beat ()
(measure
(four-on-the-floor)
(seq
(swagger)
(swagger))))
(intro-fill-1 ()
(measure
(four-on-the-floor)
(seq (swagger)
(stagger))))
(intro-fill-2 ()
(measure
(four-on-the-floor)
(seq (jagger)
(jagger))))
Finally, I've built up to defining the music. Here, the para (parallel) operator combines its two inputs: a four measure drum pattern, constructed in an AAAB pattern from intro-beat and intro-fill-1, and a sequence of four arpeggiated chords, each one measure long. This defines the first four measures of the music:
(para
(phrase-aaab
(intro-beat)
(intro-fill-1))
(seq
(measure (fat-arp 128 '(0.00 0 3 7 11) :rate 4 :volume (volramp 8 -1/22)))
(measure (fat-arp 128 '(0.00 0 2 5 8) :rate 4 :volume (volramp 8 -1/22)))
(measure (fat-arp 128 '(0.00 -2 7 8 12) :rate 4 :volume (volramp 9 -1/20)))
(measure (fat-arp 128 '(0.00 -1 2 3 7) :rate 4 :volume (volramp 10 -1/18)))))
That's basic macro expansion that does all the right thing and has full programming language power inside the macro expanders. It's much higher level than you'd get from other macro options, and is still straight assembly instruction & byte-level definitions under user control.
tl;dr: Write a 6502 assembler as a DSL inside an existing programming environment that already does all the cool & solid macro stuff.