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

(Примечание для обеспокоившихся: я знаю, знаю, все это очень неэффективно. В промышленной программы мы, возможно, предприняли бы шаги чтобы избежать такого глубокого вложения вызовов процедур. Не волнуйтесь об этом. Это упражнение, помните? Более важно сделать его правильно и понять его, чем получить неправильный ответ но быстро. Если вы закончите свой компилятор и обнаружите, что вы несчастны от его быстродействия, вы вольны вернуться и доработать код для более быстрой работы).

Было бы хорошей идеей протестировать программу сейчас. Так как мы пока не имеем процедуры для работы с операциями присваивания, я просто добавил строки:

Load('A');

Load('B');

Load('C');

Load('X');

в основную программу. Таким образом, после того, как раздел объявления завершен, они будут выполнены чтобы генерировать код для загрузки. Вы можете поиграть с различными комбинациями объявлений чтобы посмотреть как обрабатываются ошибки.

Я уверен, что вы не будете удивлены, узнав, что сохранение переменных во многом подобно их загрузке. Необходимые процедуры показаны дальше:

{–}

{ Store Primary to Variable }

procedure StoreVar(Name, Typ: char);

begin

EmitLn('LEA ' + Name + '(PC),A0');

Move(Typ, 'D0', '(A0)');

end;

{–}

{ Store a Variable from the Primary Register }

procedure Store(Name: char);

begin

StoreVar(Name, VarType(Name));

end;

{–}

Вы можете проверить их таким же образом, что и загрузку.

Теперь, конечно, достаточно легко использовать их для обработки операций присваивания. Что мы сделаем – создадим специальную версию процедуры Block, которая поддерживает только операции приваивания, а также специальную версию Expression, которая поддерживает в качестве допустимых выражений только одиночные переменные. Вот они:

{–}

{ Parse and Translate an Expression }

procedure Expression;

var Name: char;

begin

Load(GetName);

end;

{–}

{ Parse and Translate an Assignment Statement }

procedure Assignment;

var Name: char;

begin

Name := GetName;

Match('=');

Expression;

Store(Name);

end;

{–}

{ Parse and Translate a Block of Statements }

procedure Block;

begin

while Look <> '.' do begin

Assignment;

Fin;

end;

end;

{–}

(Стоит заметить, что новые процедуры, которые позволяют нам манипулировать типами, даже проще и яснее чем те, что мы видели ранее. Это в основном блягодаря нашим усилиям по изоляции подпрограмм генерации кода.)

Есть одна небольшая назойливая проблема. Прежде мы использовали завершающую точку Паскаля чтобы выбраться из процедуры TopDecl. Теперь это неправильный символ... он использован для завершения Block. В предудущих программах мы использовали для выхода символ BEGIN (сокращенно "b"). Но он теперь используется как символ типа.

Решение, хотя и является отчасти клуджем, достаточно простое. Для обозначения BEGIN мы будем использовать 'B' в верхнем регистре. Так что измените символ в цикле WHILE внутри TopDecl с "." на "B" и все будет прекрасно.

Теперь мы можем завершить задачу, изменив основную программу следующим образом:

{–}

{ Main Program }

begin

Init;

TopDecls;

Match('B');

Fin;

Block;

DumpTable;

end.

{–}

(Обратите внимание, что я должен был расставить несколько обращений к Fin чтобы избежать проблем переносов строк.)

ОК, запустите эту программу. Попробуйте ввести:

ba { byte a } *** НЕ НАБИРАЙТЕ КОММЕНТАРИИ!!! ***

wb { word b }

lc { long c }

B { begin }

a=a

a=b

a=c

b=a

b=b

b=c

c=a

c=b

c=c

.

Для каждого объявления вы должны получить сгенерированный код, распределяющий память. Для каждого присваивания вы должны получить код который загружает переменную корректного размера и сохраняет ее, также корректного размера.

Есть только одна небольшая проблема: сгенерированный код неправильный!

Взгляните на код для a=c:

MOVE.L C(PC),D0

LEA A(PC),A0

MOVE.B D0,(A0)

Этот код корректный. Он приведет к сохранению младших восьми бит C в A, что является примлемым поведением. Это почти все, что мы можем ожидать.

Но теперь, взгляните на противоположный случай. Для c=a генерируется такой код:

MOVE.B A(PC),D0

LEA C(PC),A0

MOVE.L D0,(A0)

Это не правильно. Он приведет к сохранению байтовой переменной A в младших восьми битах D0. Согласно правилам для процессора 68000 старшие 24 бита останутся неизменными. Это означаем, что когда мы сохраняем все 32 бита в C, любой мусор, который был в этих старших разрядах, также будет сохранен. Нехорошо.

То, с чем мы сейчас столкнулись назвается проблемой преобразования типов или приведением.

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных