The problem with giving only a limited support for something is that people will invariably want more and start to abuse the system. For instance with operators you risk ending up with a slew of little languages full of glyphs rich with semantic meaning (think Perl).
Macros allow you to build "up", to add new [abstraction] layers to your language but sometimes it would be nice to be able to go "down" as well and add new semantics that non-trivially interacts with the host language. Re-entrant continuations or proper tail recursion for CL come to mind. Another example of such friction is Qi [http://www.lambdassociates.org/aboutqi.htm] where all sorts of hacks (case sensitivity etc.) are needed instead of it simply being a library.
Theoretically one could design a language powerful enough that this would never be necessary but even then you would want code-walkers for optimisations. CL with it's compiler macros is a step in the right direction but it soon runs aground when you want to do things such CPS optimisations. Say you want to merge nested map-operations in CL:
(map 'vector #'^2 (map 'vector #'+ a b))
=>
(map (lambda (:g1 :g2) (^2 (+ :g1:g2))) a b)
This is something compiler macros are great for, but as soon as the inner map is wrapped in a function we have a problem. What our compiler macro sees is something like:
(map 'vector #^2 (vector+ a b))
and at that point we have no idea what vector+ looks like.
In terms of a compromise, access to the environment at compile-time would go a long way (CL has provisions for this, but the standard doesn't say anything about how the environment should look like) and maybe a facility to get function definitions (forced inlining if you will).