Близится релиз языка NewLang с принципиальной новой «фишкой», переделанным вариантом препроцессора, который позволяет расширять синтаксиса языка для создания различных диалектов DSL за счет макросов. И, как всегда, используя ранее найденный лайфхак Хабр — ума палата, хотелось бы получить от читателей обратную связь насчет предлагаемого ниже подхода, который планируется к реализации в новом препроцессоре NewLang. Далее речь пойдет о втором варианте, а именно, о реализации DSL на базе языков (метаязыков) общего назначения и новом варианте реализации макросов в NewLang как основы для разработки DSL. Наверно имеет смысл начать с описания о двух крайностях при реализации DSL на базе языка (метаязыка) общего назначения: Если язык программирования ограничен собственной фиксированной грамматикой и не допускает её расширения, то при реализации DSL разработчик будет вынужден использовать уже существующую грамматику, правила записи операций и вообще весь синтаксис будет оставаться такими же, как в языке реализации. Например, при использовании в качестве базового языка С/С++ или применении различных библиотек и фреймворков в других языках программирования общего назначения. В этом случае под термином "DSL" будет скрываться просто набор специфических терминов предметной области, переопределенных макросов и/или операторов, но использование которых будет ограничено грамматикой языка реализации. Если же язык (метаязык) позволяет модифицировать собственную грамматику (например на уровне AST), то DSL уже не будет жестко огранен синтаксисом базового языка программирования, и в результате его грамматика может быть какой угодно. Вплоть до того, что «для каждого нового проекта придется изучать новый язык… ». Это можно сделать с помощью использования специализированных метаязыков (Lisp, ML, Haskell, Nemerle, Forth, Tcl, Rebol и пр.) Очень рекомендую прочитать о метапрограммровании великолепную статью NeoCode Метапрограммирование: какое оно есть и каким должно быть.  «Нет в мире совершенства», и после выпуска релиза NewLang 0.2 я получил много отзывов (по большей части негативных), по поводу первого варианта реализации макросов и DSL на их основе. И если положить руку на сердце, эта критика часто была обоснованной. Поэтому я решил попробовать немного переделать макросы, в надежде получить «золотую середину» между двумя описанными выше крайностями при описании DSL. Макросы в NewLang, это один или несколько терминов, которые заменяются на другой термин или на целую синтаксическую конструкцию (последовательность лексем). Макросы являются одновременно и расширением базового синтаксиса языка, при реализации собственных диалектов DSL, и синтаксическим сахаром.  Главная особенность макросов в том, что они позволяют изменять выражения еще до их вычисления во время выполнения. Раскрытие макросов происходит во время работы лексера, что позволяет подменять ими любые другие термины и даже модифицировать сам синтаксис языка.  Поэтому, если перед именем объекта NewLang модификатор не указывать (\макрос, $локальная_переменная или @модуль), то сперва будет производиться поиск объекта среди макросов, потом среди локальных переменных и в последнюю очередь среди модулей (объектов модуля). За счет этого можно использовать термины без обязательных модификаторов для указания конкретных типов объектов. Для определения макросов используется точно такой синтаксис, как и для других объектов языка (применяются операторы «::=», «=» или «:=», соответственно для создания нового объекта, присвоение нового значения уже существующему или для создания объекта / присвоения нового значения объекту не зависимо от его наличия или отсутствия).  В общем виде, определение макроса состоит из трех частей <имя макроса> <оператор создания/присвоения> <тело макроса> и завершающая точка с запятой ";". Телом макроса могут быть корректное выражение языка, последовательность лексем (которые заключается в двойные обратные слеши, т.е. \\лексема1 лексема1\\) или обычная текстовая строка (обрамленная в тройные обратные слеши, т.е. \\\ текстовая строка \\\).  Для соединения двух лексем в одну (аналог операции ## в препроцессоре С/С++), используется по аналогии синтаксис ##. Похожий оператор применяется и для обрамления лексемы в кавычки #, например, \macro($arg) := \\ func_ \## \#arg(\#arg) \\;? тогда вызов macro(arg) будет преобразован в func_arg ("arg"); Именем макроса может быть одиночный идентификатор с префиксом макроса "\" или последовательность из нескольких лексем. Если в качестве имени макроса используется последовательность лексем, то среди них должен быть как минимум один идентификатор и может присутствовать один или несколько шаблонов.  Шаблон — это специальный идентификатор который при сопоставлении может заменяться любым одиночным термином. С помощью шаблонов производится поиск по образцу и замена заданных последовательностей лексем на тело макроса. Для указания шаблона в начале идентификатора нужно поставить знак доллара (что соответствует записи имени локальной переменой), т. е. \\одна_лексема\\, \\целых три лексемы\\ \\лексема $шаблон1 $шаблон2 \\.  Макросы считаются одинаковыми, если их идентификаторы равны, количество элементов в их именах совпадает, а идентификаторы и шаблоны располагаются на тех же самых местах. Термины или шаблоны в имени макроса могут иметь аргументы, которые указываются в круглых скобках. Переданные аргументы в теле макроса записываются в месте для раскрытия как имя локальной переменой, но перед именем нужно добавить обратный слеш, т.е. \$name. Произвольное количество параметров у макроса отмечается троеточием "...", а место для вставки этих аргументов отмечается лексемой \$.... Если у макроса есть несколько идентификаторов с аргументами, то для вставки аргументов из конкретного идентификатора используется лексема с указанием нужного идентификатора, например, \$name.... Чтобы вставить количество реально переданных аргументов используется лексема \$#, или с указанием нужного идентификатора, например, \$#name. Макросы работают с лексемами, которые содержат различную информацию, в том числе и о типе данных, если она указана. Но на текущий момент типы данных в аргументах макросов никак не обрабатываются и это одна из обязательных фич, которая будет реализована в будущем. Таким образом можно определить макросы в следующих комбинациях: Каждая из перечисленных выше комбинации имеет свои свойства и ограничения:  Классическая замена одного термина на другой термин или целое выражение. Однократно обрабатывается лексером и парсером при определении. Выражение в теле макроса должно быть корректным с точки зрения синтаксиса и при наличии в нем ошибок, сообщение об этом формируется сразу, еще при определении макроса. Классическая замена одного термина на последовательности лексем, в том числе и не полные синтаксические конструкции. Однократно обрабатывается лексером при определении макроса. Тело макроса анализируется парсером при его использовании, поэтому возможные синтаксические ошибки будут замечены только при раскрытии макроса. Классическая замена одного термина на текстовую строку, которая подается на вход лексера. Однократно обрабатывается лексером только имя макроса при его определении, что позволяет модифицировать тело макроса и изменять/комбинировать/модифицировать лексемы до их подачи в анализатор. Синтаксические ошибки будут замечены только при раскрытии макроса. 4, 5 и 6. Замена последовательности из нескольких лексем (шаблонов) на выражение, последовательность лексем или текстовую строку соответственно. Макросы используются и для преобразования базового синтаксиса NewLang в более привычный синтаксис на основе ключевых слов, так как такой текст гораздо легче воспринимается при последующем чтении исходного кода. Если перед именем объекта NewLang модификатор не указан (\макрос, $локальная_переменная или @модуль), то сперва ищется имя макроса, потом имя локальной переменной и в последнюю очередь имя модуля (объекта модуля). За счет этого получается определять синтаксис DSL в привычной записи без обязательных префиксов у разных типов объектов.  Например, запись условного оператора на основном синтаксисе NewLang: Или цикл до 5: будет выглядеть более привычно с использованием соответствующих макросов: Для удаления макроса нужно присвоить ему пустую последовательность лексем \macro_str := \\\\;. Так же для удаления можно использовать специальный синтаксис: \\\\ name \\\\; или \\\\ \\два термина\\ \\\\;, т.е. указать имя макроса между четырьмя обратными слешами. Необходимость использования отдельной синтаксической конструкции для удаления макросов вызвана тем, что имена макросов обрабатываются лексером еще до этапа анализа в парсере. Буду благодарен за любую обратную связь по данной реализации макросов. И дважды благодарен, если кроме критики будут высказаны еще и предложения по её улучшению и доработкам, если какой-то момент был упущен.  Системный архитектор