Также хочу отметить что 3 подзадачи не равноценны по сложности
Синтез кода из дерева - тривиальная прикладная задача
Семантика - чутка посложнее, но в вашем случае не сильно
А вот синтаксис - представляет собой основную сложность всей задачи
Поэтому я бы предложил пересмотреть план оплаты, перебросив большую часть оплаты в первую часть, и в свою очередь разбив ее на несколько частей, с постепенно нарастающим синтаксисом
В качестве первой вехи(рискую предположить, что на этом этапе уже часть разработчиков отсеется после пробы), поддержать синтаксис только объявление переменных с таким тестовым примером
int a = 1, b, c = 2;
int d = 3;
Его особенность в том, что в нем есть
1. под-список из разных типов нод(VariableDeclarator с инициализацией и без)
2. под-список из одинаковых сущностей(VariableDeclaration-ы)
Захват под-списка, без зацикливания - это один из примеров, который отделяет правильно выбранную архитектуру для данного типа грамматики
Затем усложнить пример до
int a = 1, b, c = 2;
cout << a;
int d = 3;
Тут уже VariableDeclaration-ы перемешаны с Statement-ами
Ну а затем остальные пункты синтаксиса