292
настолько простой, насколько возможно, я не думаю, что мы должны делать это за счет
приемлемости. Исправления подобные этому, приведут к потере основной детали,
которая заключается в том, чтобы логическое "not" просто не является тем же самым что
унарный минус. Рассмотрим исключающее "or", которое обычно записывается так:
a~b ::= (a and not b) or (not a and b)
Если мы разрешим "not" изменять весь терм, последний терм в круглых скобках
интерпретировался бы как:
not(a and b)
что совсем не то же самое. Так что ясно, что о логическом "not" нужно думать как о
связанном с показателем а не термом.
Идея перегрузки оператор '~' не имеет смысла и с математической точки зрения.
Применение унарного минуса эквивалентно вычитанию из нуля:
-x <=> 0-x
Фактически, в одной из моих более простых версий Expression я реагировал на
ведущий addop просто предзагружая нуль, затем обрабатывая оператор как если бы это
был двоичный оператор. Но "not" это не эквивалент исключающему или с нулем... которое
просто возвратит исходное число. Вместо этого, это исключающее или с FFFFh или -1.
Короче говоря, кажущаяся близость между унарным "not" и унарным минусом
разваливается при более близком исследованиии. "not" изменяет показатель а не терм и
он не имеет отношения ни к унарному минусу, ни исключающему или. Следовательно, он
заслуживает своего собственного символа для вызова. Какой символ лучше, чем
очевидный, также используемый в Си символ "!"? Используя правила того как мы думаем
должен вести себя "not", мы должны быть способны закодировать исключающее или
(предполагая что это нам когда-нибудь понадобится) в очень естественной форме:
a & !b | !a & b
Обратите внимание, что никаких круглых скобок не требуется - выбранные нам уровни
приоритета автоматически заботятся обо всем.
Если вы продолжаете учитывать уровни приоритета, это определение помещает '!' на
вершину кучи. Уровни становятся:
1. !
2. - (унарный)
3. *, /, &
4. +, -, |, ~
Рассматривая этот список, конечно не трудно увидеть, почему мы имели проблему при
использовании '~' как символа "not"!
Так, как мы механизируем эти правила? Таким же самым способом, как мы сделали с
SignedTerm, но на уровне показателя. Мы определим процедуру NotFactor:
{ Parse and Translate a Factor with Optional "Not" }
procedure NotFactor;
begin
if Look ='!' then begin
Match('!');
Factor;
Notit;
end
else
Factor;
end;
и вызовем ее из всех мест, где мы прежде вызывали Factor, т.е. из Term, Multiply, Divide и
_And. Обратите внимание на новую процедуру генерации кода: