На мой взгляд, обычный генератор лексеров и / или парсеров обычно не сильно помогает в написании ассемблера. Они в основном полезны при работе с относительно сложными грамматиками, но в случае ассемблера «грамматика» обычно настолько тривиальна, что такой генератор является скорее помехой, чем помощью.
Типичный ассемблер в основном управляется таблицами - вы начинаете с создания таблицы определенных кодов операций и характеристик инструкции, которую она будет генерировать (например, число и типы регистров, которые должны быть указаны для нее). Обычно у вас есть таблица (меньше, в случае шейдеров, вероятно, намного меньше), определяющая, как кодировать режимы адресации и тому подобное.
Большая часть ассемблера работает с этой таблицей, т. Е. Она читает что-то из входных данных и пытается найти это в таблице. Если его нет, выдается сообщение об ошибке, в котором говорится, что это неизвестный код операции. Если он найден, он получает информацию из таблицы о количестве операндов, связанных с этим кодом операции. Он пытается прочитать столько операндов. Если это невозможно, выдает ошибку, сообщающую, что с инструкцией что-то не так. Если это возможно, он кодирует инструкцию и начинает заново.
Конечно, есть несколько мест, с которыми он должен справиться. Где / когда вы определяете что-то вроде метки, оно должно записывать название и позицию этой метки в таблице символов. Когда он сталкивается с чем-то вроде ответвления по этому адресу, он должен найти цель и соответствующим образом закодировать свой адрес.
Только когда / если вы решите поддерживать макросы, вы сильно отойдете от этой базовой модели. В зависимости от того, насколько тщательно вы их освоите, может быть целесообразно использовать генератор синтаксических анализаторов и тому подобное для средства расширения макросов. Опять же, учитывая, что шейдеры в основном довольно маленькие, макросы вряд ли будут иметь высокий приоритет для такого ассемблера.
Редактировать: перечитывая его, я, вероятно, должен уточнить / исправить одну точку. Использование генератора синтаксического анализатора не так много, когда сама грамматика становится сложной, как когда грамматика допускает сложные операторы. Рассмотрим действительно тривиальную грамматику:
expression := expression '+' value
| expression '-' value
| value
Несмотря на то, что это допускает только сложение и вычитание, оно все же определяет операторы, которые являются произвольно сложными (или, по крайней мере, произвольно длинные строки значений, которые добавляются или вычитаются). Конечно, даже для довольно тривиального реального языка у нас обычно есть умножение, деление, вызовы функций и т. Д.
Это значительно отличается от типичного языка ассемблера, где каждая инструкция имеет фиксированный формат. Например, операция сложения или вычитания имеет ровно два операнда-источника и один операнд-адресат.