Если у вас есть модель грамматики в нормализованной форме (все правила, как это):
LHS = RHS1 RHS2 ... RHSn ;
и язык prettyprinter (например, AST для преобразования текста), вы можете довольно легко создать один из них.
Просто начните с символа цели в виде дерева юнитов.
Repeat until no nonterminals are left:
Pick a nonterminal N in the tree;
Expand by adding children for the right hand side of any rule
whose left-hand side matches the nonterminal N
Для терминалов, которые содержат значения (например, имена переменных, числа, строки, ...), вам придется генерировать случайный контент.
Сложность описанного выше алгоритма состоит в том, что он явно не завершается. Что вы на самом деле хотите сделать, так это выбрать некоторое ограничение на размер вашего дерева и запускать алгоритм до тех пор, пока все нетерминалы не исчезнут или вы не превысите этот предел. В последнем случае вернитесь назад, отмените последнюю замену и попробуйте что-нибудь еще. Это дает вам ограниченный поиск в глубину для поиска AST вашего определенного размера.
Тогда распечатайте результат. Это красивая часть , которую трудно понять.
[Вы можете собрать все эти вещи самостоятельно, включая симпатичный принтер, но это довольно трудоемкий труд. Я создаю инструменты, которые включают весь этот механизм непосредственно в параметризованном языке; смотри мою биографию].
Противная проблема даже с хорошо сформированными AST заключается в том, что они могут быть бессмысленными; вы можете создать объявление целого числа X и присвоить ему строковое литеральное значение для языка, который этого не допускает. Возможно, вы можете устранить некоторые простые проблемы, но семантика языка может быть невероятно сложной, рассмотрим C ++ в качестве примера. Гарантировать, что вы получите семантически значимую программу, чрезвычайно сложно; по сути, вы должны проанализировать полученный текст и выполнить разрешение и проверку имени и типа. Для C ++ вам нужен полный интерфейс C ++.