All macros take raw forms as parameters and perform a replacement on their body. The trick of implementing a macro system is to tell your lazy compiler.
To put in another way, when the compiler encounters a function, it first evaluates its list of formal parameters, gives the results and passes them to the function. When the compiler finds a macro, it passes arguments that have no analogues in the body, then performs any calculations that the body asks for, and finally replaces the result.
For example, let's say you have a function:
(defun print-3-f (x) (progn (princ x) (princ x) (princ x)))
and macro:
(defmacro print-3-m (x) `(progn (princ ,x) (princ ,x) (princ ,x)))
Then you can immediately see the difference:
CL-USER> (print-3-f (rand)) * 234 * 234 * 234 CL-USER> (print-3-m (rand)) * 24 * 642 * 85
To understand why this is so, you need, as it were, to run the compiler in your head.
When a Lisp function encounters a function, it builds a tree in which (rand) first evaluated, and the result is passed to the function, which prints the specified result three times.
On the other hand, when Lisp gets into the macro, it passes the (rand) form intact to the body, which returns a list with quotes, where x is replaced by (rand) , giving:
(progn (princ (rand)) (princ (rand)) (princ (rand)))
and replace the macro call for this new form.
Here you will find a wealth of documentation on macros in various languages, including Lisp.