Another hack I use for syntax-rules macros is to modify the definition.  Here's a macro from JRM's Syntax-Rules Primer for the Mildly Eccentric:

(define-syntax bind-variables
   (syntax-rules ()
     ((bind-variables () form . forms)
      (begin form . forms))

     ((bind-variables ((variable value0 value1 . more) . more-bindings) form . forms)
      (syntax-error "bind-variables illegal binding" (variable value0 value1 . more)))

     ((bind-variables ((variable value) . more-bindings) form . forms)
      (let ((variable value)) (bind-variables more-bindings form . forms)))

     ((bind-variables ((variable) . more-bindings) form . forms)
      (let ((variable #f)) (bind-variables more-bindings form . forms)))

     ((bind-variables (variable . more-bindings) form . forms)
      (let ((variable #f)) (bind-variables more-bindings form . forms)))

     ((bind-variables bindings form . forms)
      (syntax-error "Bindings must be a list." bindings))))
And here's what I do to it:
(define-syntax bind-variables
   (syntax-rules ()
     ((bind-variables () form . forms)
      '(begin form . forms))

     ((bind-variables ((variable value0 value1 . more) . more-bindings) form . forms)
      '(syntax-error "bind-variables illegal binding" (variable value0 value1 . more)))

     ((bind-variables ((variable value) . more-bindings) form . forms)
      '(let ((variable value)) (bind-variables more-bindings form . forms)))

     ((bind-variables ((variable) . more-bindings) form . forms)
      '(let ((variable #f)) (bind-variables more-bindings form . forms)))

     ((bind-variables (variable . more-bindings) form . forms)
      '(let ((variable #f)) (bind-variables more-bindings form . forms)))

     ((bind-variables bindings form . forms)
      '(syntax-error "Bindings must be a list." bindings))))

By inserting the ' mark before the right side of each rewrite rule, when I invoke nth-value it will display the code rather than evaluating it. This does not handle recursion or hygiene, though.  If you want it to handle hygiene, don't use quote but wrap each right side in (write ...) instead.

On Thu, Oct 3, 2019 at 2:43 PM Arthur A. Gleckler <xxxxxx@speechcode.com> wrote:
On Thu, Oct 3, 2019 at 8:30 AM Lassi Kortela <xxxxxx@lassi.io> wrote:
Has someone here by chance written a pre-SRFI for macroexpand (or
macro-expand, syntax-expand, etc.)? Would be nice to have a standard way
to find out what code your macros expand to.

Since Scheme has several macro systems (syntax-rules, syntax-case,
CL-style define-macro, maybe others?) does that complicate the interface
of a macroexpander, or is the complexity all in the internals?

As Marc points out, that sounds like a hard task, especially given the variety of approaches different Scheme implementations take to macros.

Under MIT Scheme, what I do is evaluate (pp (lambda () <macro-definition>)).  That pretty prints the expanded form without executing it.  Given a pretty printer or some other means of printing the sources of a procedure, I wouldn't be surprised if that worked on other implementations.