En primer lugar se lo recomendaría leer el capítulo 9 (notación) de The Practice of Programming de Kernighan y Pike.
Cuando haya hecho eso, vuelva aquí con preguntas específicas sobre cómo asignar los conceptos de ese capítulo a diseños específicos para los problemas que desea resolver.
El patrón básico es escribir un intérprete al que se le pasa un argumento 'comando', y posiblemente un argumento 'entorno' y ejecuta el comando (en el entorno). A continuación, tiene la opción de escribir un analizador sintáctico, que toma una cadena de 'secuencia de comandos' y la convierte en un objeto 'comando' válido (es decir, un DSL externo); o proporciona una biblioteca para ayudar a los usuarios a crear el objeto 'comando' explícitamente en el mismo idioma que está usando (DSL interno).
Kernighan y Pike hacen un buen trabajo demostrando cuán trivial y cuán complejo puede ser un intérprete. Si desea más profundidad, le sugiero que lea The Essentials of Programming Languages por Daniel Friedman et al. Que construye al menos un intérprete diferente por capítulo y demuestra cómo implementar características tales como variables, funciones, ámbitos, objetos, clases, tipado estático y continuaciones.
Sin embargo, le sugiero que intente primero con una DSL trivial, de lo contrario, todo es solo teoría; un libro es mucho más interesante cuando lo hace relevante y práctico según su experiencia previa.
Sugerencia seria: Implementar utilizando Groovy, Scala o Clojure. – Mike
Eso depende totalmente de cuán complicado le gustaría que fuera el DSL. – NawaMan
+1 por no usar Java para esto. En todo caso, usaría Ruby (o JRuby). – cletus