Como faço para inferir o uso de parênteses ao traduzir uma árvore de expressão?

Eu estou trabalhando na tradução de uma árvore de expressão para um formato que se assemelha a notação infixa; Não estou avaliando a árvore ou executando suas operações. A árvore contém operações lógicas e relacionais, e eu gostaria de emitir parênteses de uma maneira inteligente durante a tradução.

Para ilustrar, considere a seguinte expressão planejada:

a < x & (a < y | a == c) & a != d

Se eu percorrer a árvore de expressões produzida por essa expressão em ordem, então imprimai a seguinte expressão, que é incorreta.

a < x & a < y | a == c & a != d
// equivalent to (a < x & a < y) | (a == c & a != d)

Alternativamente, eu posso novamente realizar uma travessia em ordem, mas emitir parênteses antes e depois de processar uma expressão binária. Isso produzirá a seguinte expressão correta, mas com vários parênteses redundantes.

(((a < x) & ((a < y) | (a == c))) & (a != d))

Existe um algoritmo de travessia de árvore de expressão que produz expressões com ótimo parênteses?

Para referência, aqui está um trecho doExpressionVisitor Eu estou usando para inspecionar a árvore.

class MyVisitor : ExpressionVisitor
{
    protected override Expression VisitBinary(BinaryExpression node)
    {
        Console.Write("(");

        Visit(node.Left);
        Console.WriteLine(node.NodeType.ToString());
        Visit(node.Right);

        Console.Write(")");

        return node;
    }

    // VisitConstant, VisitMember, and VisitParameter omitted for brevity.
}

questionAnswers(2)

yourAnswerToTheQuestion