Давайте создадим компилятор!

ОглавлениеДобавить в закладки К обложке

Булево «AND»

С это небольшой философией, мы можем приступить к оператору «and», который пойдет в процедуру Term. К настоящему времени вы возможно сможете сделать это без меня, но в любом случае вот код:

В Scanner:

{–}

function IsMulop(c: char): boolean;

begin

IsMulop := c in ['*','/', '&'];

end;

{–}

в Parser:

{–}

procedure Term;

begin

Factor;

while IsMulop(Look) do

case Look of

'*': Multiply;

'/': Divide;

'&': _And;

end;

end;

{–}

{ Parse and Translate a Boolean And Operation }

procedure _And;

begin

Match('&');

Push;

Factor;

PopAnd;

end;

{–}

и в CodeGen:

{–}

{ And Primary with TOS }

procedure PopAnd;

begin

EmitLn('AND (SP)+,D0');

end;

{–}

Ваш синтаксический анализатор теперь должен быть способен обрабатывать почти любые виды логических выражений а также (если вы хотите) и смешанные выражения.

Почему не «все виды логических выражений»? Потому что пока мы не имели дела с логическим оператором «not» и с ним все становится сложнее. Логический оператор «not» кажется на первый взгляд идентичным в своем поведении унарному минусу, поэтому моей первой мыслью было позволить оператору исключающего или, '~', дублировать унарный «not». Это не работало. При моей первой попытке процедура SignedTerm просто съедала мой '~' потому что символ проходил проверку на addop но SignedTerm игнорировал все addop за исключением "-". Было бы достаточно просто добавить другую строку в SignedTerm, но это все равно не решит проблему, потому что, заметьте, Expression принимает терм со знаком только для первого аргумента.

Математически, выражение типа:

–a * -b

имеет небольшой или совсем никакого смысла и синтаксический анализатор должен отметить его как ошибку. Но то же самое выражение, использующее логическое «not», имеет точный смысл:

not a and not b

В случае с этими унарными операторами выбор заставить их работать таким же самым способом кажется исскуственным принуждением, жертвованием примлемым поведением на алтаре простоты реализуемости. Хотя я полностью за сохранение реализации настолько простой, насколько возможно, я не думаю, что мы должны делать это за счет приемлемости. Исправления подобные этому, приведут к потере основной детали, которая заключается в том, чтобы логическое «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

Обратите внимание, что никаких круглых скобок не требуется – выбранные нам уровни приоритета автоматически заботятся обо всем.

Если вы продолжаете учитывать уровни приоритета, это определение помещает '!' на вершину кучи. Уровни становятся:

!

– (унарный)

*, /, &

+, -, |, ~

Рассматривая этот список, конечно не трудно увидеть, почему мы имели проблему при использовании '~' как символа «not»!

Так, как мы механизируем эти правила? Таким же самым способом, как мы сделали с SignedTerm, но на уровне показателя. Мы определим процедуру NotFactor:


Логин
Пароль
Запомнить меня