Это можно сделать в случае действия уменьшения YACC для оператора не (!) При строительстве АСТ. Вы можете написать любой код в семантическом действии. Вместо «слепо» сборки узла дерева для не из его дочернего элемента (обычный код, который вы найдете в таком сокращающем действии), вы можете написать код, который проверил бы ребенка, чтобы узнать, была ли у него требуемая форма, и если поэтому построим древообразное дерево де Моргана каждого. Код, чтобы сделать это немного грязно, потому что он должен лезть вверх и вниз по дереву, сопоставляя узлы и переставляя поддеревья, но его просто yuck и неплохо. Обратите внимание, что закон Де Моргана, возможно, применим к детям, имеющим форму как (A & & B) || C) и (A || B & & C)), поэтому вы должны обрабатывать два основных подсекции.
Я согласен с Len; вы обычно не делали бы этого в парсере. Его цель - настроить вас на более сложные действия, и если DeMorganizing не будет единственной целью, вам понадобится другой код для обработки AST в разных случаях, после того, как разборок завершен, так почему бы не оставить всю обработку до тех пор, пока она не появится?
Следуя этой идее, мой recent SO answer on eliminating configured-dead code упрощает символическую логическую логику; он показывает один из способов преобразования логических логических АСТ с использованием преобразований источника в источник с использованием шаблонов. Такой подход позволяет избежать инкубирования/взлома кода yucky tree. Должно быть очевидно, как писать читаемый превращает, что реализует закон Моргана с этой техникой (и на самом деле мы сделали сына в прошлом).
Возможно, вы имели в виду законы Мерфи с yacc :))) –