
 
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. Обратите внимание на новую процедуру генерации кода: