Посмотрел по внимательнее на генерируемый макросом код. Понял что в нем мне не нравится.
Ты, в момент разбора грамматики, строишь некое виртуальное AST. А в момент когда вызываются DoOperation и oGenerateResult в них передаются значения из этого AST.
Это плохой подход с точки зрения производительности конечного парсера.
Макрос должен генерировать вызовы методов-обработчиков в моменты когда парсер заканчивает разбор того или иного правила.
При этом нужно формировать минимум промежуточных структур. Фактически до окончания разбора подправила ты должен хранить только позиции на начало и на конец правила.
Если правило возвращает значение, то ты так же должен запомнить результат в стеке. Если все подправила спарсятся, ты должен передать эти значения в метод-обработчик, иначе про них просто нужно забыть. Таким образом при откатах отпаренные значения просто будут теряться.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.