Для простой грамматики выражений вы можете устранить (большинство) избыточных скобок, используя приоритет оператора, по сути, так же, как вы анализируете выражение в AST.
Если вы смотрите на узел вAST, все, что вам нужно сделать, это сравнить приоритет оператора узла с приоритетом оператора для аргумента, используя ассоциативность оператора в случае, когда приоритеты равны. Если оператор узла имеет более высокий приоритет, чем аргумент, аргумент не нужно заключать в скобки;иначе это нужно им. (Два аргумента должны быть рассмотрены независимо.) Если аргумент является литералом или идентификатором, то, конечно, скобки не нужны;этот особый случай можно легко обработать, сделав приоритет таких значений бесконечным (или, по крайней мере, большим, чем любой приоритет оператора).
Однако в вашем примере есть еще одно предложение по исключению избыточных скобок, основанное на математической ассоциативностиОператор. К сожалению, математическая ассоциативность не всегда применима в компьютерной программе. Если ваши выражения с числами с плавающей запятой, например, a+(b+c)
и (a+b)+c
, могут иметь очень разные значения:
(gdb) p (1000000000000000000000.0 + -1000000000000000000000.0) + 2
$1 = 2
(gdb) p 1000000000000000000000.0 + (-1000000000000000000000.0 + 2)
$2 = 0
По этой причине довольно часто компиляторы избегают изменения порядка примененияумножение и сложение, по крайней мере, для арифметики с плавающей точкой, а также для целочисленной арифметики в случае языков, которые проверяют на целочисленное переполнение.
Но если вы действительно хотите переставить на основе математической ассоциативности, вам понадобитсядополнительная проверка во время прогулки по АСТ;перед проверкой приоритета вы захотите проверить, использует ли посещаемый вами узел и его левый аргумент тот же оператор, где этот оператор математически ассоциативен. (Это предполагает, что только операторы, которые группируются слева, являются математически ассоциативными. В маловероятном случае, если у вас есть математически ассоциативный оператор, который группирует справа, вы захотите проверить посещаемый узел и его правый аргумент.)
Если это условие выполнено, вы можете повернуть корень AST, превратив (например) PROD(PROD(a,b),□))
в PROD(a,PROD(b,□))
. Это может привести к дополнительным поворотам в случае, если a
также является PROD
узлом.