Когда я писал компиляторы, я писал на языке ассемблера (то есть исходный код на языке ассемблера), который затем запускал ассемблер системы. Таким образом, я мог легко видеть, что я генерировал. mov ax, bx
(сборка x86) гораздо проще читать, чем декодировать HEX-коды операций.
Если мне не разрешили использовать ассемблер в конечном продукте, я разработал компилятор, используя вывод сборки, а затем, когда все заработало, я создал двоичный путь вывода. Прелесть в том, что все, что мне пришлось изменить, - это фактический вывод байтов (коды операций и двоичные значения, а не текст).
Я бы предложил сделать нечто подобное для вашего проекта. Изначально разработайте его для вывода MSIL, который можно собрать с помощью ILASM. Таким образом, вы можете легко проверить вывод вашего генератора кода, прочитав сгенерированный код. Если вы уверены, что ваш генератор кода работает, добавьте параметр вывода, который будет использовать Reflection.Emit
или Common Compiler Infrastructure.