Continuations are a powerful thing to know, but, for promoting DSLs, I hope no one thinks they
have to wrangle continuations to implement DSLs.
One way, if you're using Racket (or another Scheme or descendant), is to translate your DSL to normal syntax in Racket much like you'd write manually (and you can use imperative or only pure-functional features, your choice).
For example, were I implementing the language used by the first example in the article, I might say each assignment establishes a lexical scope, and simply translate the source syntax to nested `let` form syntax:
(let ((a (/ 1 (+ 1 7))))
(let ((b (* 2 (+ a (sqrt a)))))
(let ((c (/ (atan b) (+ 1 c))))
(+ c (* 2 d)))))
Or (since there wasn't any non-assignment code in between the assignments), how you might normally write it manually in Racket:
(let* ((a (/ 1 (+ 1 7)))
(b (* 2 (+ a (sqrt a))))
(c (/ (atan b) (+ 1 c))))
(+ c (* 2 d)))
To get to that target syntax, I might have my parser produce intermediate syntax as a kind of abstract syntax tree, such as:
(block
(assignment a (/ 1 (+ 1 7)))
(assignment b (* 2 (+ a (sqrt a))))
(assignment c (/ (atan b) (+ 1 c)))
(return (+ c (* 2 d))))
Which, in this case, is a simple translation of syntax objects to the nested `let`s or `let*` examples above.
Of course, for a real-world DSL, you might have very different semantics than in the simple example, but the above translation method still likely applies.
You might start your language implementation by typing examples in your language, then the equivalents in Racket, then the intermediate parse trees of your examples... and then Racket `syntax-parse` or `syntax-case` generalizations your parse tree syntax to the Racket syntax.
The examples you made might then be test cases for your translation.
And if your DSL is embeddable in Racket code, you probably don't need the parser at all -- you might just need a `define-syntax`, with `syntax-parse`, `syntax-case`, or arbitrary code to do the translation.