I think the temptation to just break down into string representations of code is very easy -- and always a bad idea. The reason it seems so natural is that we're accustomed to thinking about code as a bunch of strings. So if I need to cut'n'paste some code in my editor, the reasoning goes, why not factor out the shared text and just write code that generates the code I need?
But the abstract computation that code means is significantly different than strings of text. In dropping to text you're effectively giving up on the language itself. Any time you need to escape the structure of the language it just means the language has failed you -- like casts in C. First we used
#definefor constants, then for macros, then we want variadic macros and suddenly we have this new programming language embedded into C that is less well-thought out (pass by name! it's like m4 all over again!).
The Lisp macro solution is much more elegant, because it lets you operate on the parse tree. camlp4, the O'Caml preprocessor, lets you write macros that work with the parse tree as well but O'Caml syntax is complicated enough that it's beyond mortals. (Except for graydon, but he's kinda supermortal anyway.)
Playing with Parsec teases me with more of the functional and Haskell dream, that you can work at the level of functions and computations. It's really neat that you can take a parser
letterthat accepts a letter, then apply a function to it and get back a new parser that accepts any sequence of letters. And beyond that, the fact that they provide a whole library of parser combinators, and that the combinations of parsers can be expressed with monads and so there's no new syntax necessary... but I'm still starry-eyed and it's all a little mysterious to me, still.
PS: I'm fully aware that I've given no consideration to practicality. Whatever.