Night has been enlightening. I understand my error. Instead of having multiple macros `algo1`, `evaluate`, etc. that are called when Nim compiler evaluates the syntax tree from the `dsl```call, I must see ``dsl` as a compiler itself. Now, I have only one macro, `dsl`, that is used to convert its argument to an AST, and then this AST is parsed/translated by procs in a new AST that will be used by the Nim compiler.
Instead of having multiple small macros that don't play well together and have only a local context, I'll apply a visitor-like pattern and I can control the scopes in the DSL. Thanks @dawkot for forcing me to think out of the box with your example.