Лекции по построению компилятора на Pascal

       

МОДУЛЬ OUTPUT


Конечно, каждая приличная программа должна выводить результат и наша не исключение. Наши подпрограммы вывода включают функции Emit. Код для соответствующего модуля показан дальше:

{--------------------------------------------------------------}

unit Output;

{--------------------------------------------------------------}

interface

procedure Emit(s: string);   { Emit an instruction  }

procedure EmitLn(s: string);  { Emit an instruction line }

{--------------------------------------------------------------}

implementation

const TAB = ^I;

{--------------------------------------------------------------}

{ Emit an Instruction }

procedure Emit(s: string);

begin

 Write(TAB, s);

end;

{--------------------------------------------------------------}

{ Emit an Instruction, Followed By a Newline }

procedure EmitLn(s: string);

begin

 Emit(s);

 WriteLn;

end;

end.

{--------------------------------------------------------------}

(Заметьте, что этот модуль не имеет раздела инициализации, так что он не требует блока begin.)

Проверьте этот модуль с помощью следующей основной программы:

{--------------------------------------------------------------}

program Test;

uses WinCRT, Input, Output, Scanner, Parser;

begin

 WriteLn('MAIN:");

 EmitLn('Hello, world!');

end.

{--------------------------------------------------------------}

Увидели ли вы что-либо, что удивило вас? Вы возможно были удивлены видеть, что вам было необходимо что-то набрать даже хотя основная программа не требует никакого ввода. Дело в разделе инициализации модуля Input, который все еще требует поместить что-либо в предсказывающий символ. Жаль, нет никакого способа выйти из этого, или скорее, мы не хотим выходить. За исключением простых тестовых случаев, как этот, нам всегда будет необходим допустимый предсказывающий символ, так что самое лучшее, что мы можем сделать с этой "проблемой" это... ничего.

Возможно более удивительно то что символ TAB не имеет никакого эффекта; наша строка "инструкций" начинается с первой колонки, так же как и фальшивая метка... Правильно: WinCRT не поддерживает табуляцию. У нас проблема.


Есть несколько способов, с помощью которых мы можем решить эту проблему. Один из вариантов того что мы можем сделать - просто игнорировать ее. Каждый ассемблер, который я когда либо использовал, резервируют колонку 1 для меток и взбунтуется когда увидит, что в ней начинаются инструкции. Так что, по крайней мере, мы должны сдвинуть инструкции на одну колонку чтобы сделать ассемблер счастливым. Это достаточно просто сделать: просто измените в процедуре Emit строку:

    Write(TAB, s);

на

    Write(' ', s);

Я должен признать что сталкивался с этой проблемой раньше и находил себя меняющим свое мнение так часто как хамелеон меняет цвет. Для наших целей, 99% которых будет проверка выходного кода при выводе на CRT, было бы хорошо видеть аккуратно сгруппированный "объектный" код. Строка:

    SUB1:  MOVE #4,D0

просто выглядит более опрятно, чем отличающийся, но функционально идентичный код:

    SUB1:

     MOVE #4,D0

В тестовой версии моего кода я включил более сложную версию процедуры PostLabel, которая позволяет избежать размещения меток на раздельных строках, задерживая печать метки чтобы она оказалась на той же самой строке, что и связанная инструкция. Не позднее чем час назад, моя версия модуля Output предоставляла полную поддержку табуляции с использованием внутренней переменной счетчика столбцов и подпрограммы для ее управления. Я имел некоторый довольно изящный код для поддержки механизма табуляции с минимальным увеличением кода. Было ужасное искушение показать вам эту "красивую" версию, единственно чтобы покрасоваться элегантностью.

Однако, код "элегантной" версии был значительно более сложным и большим. После этого у меня появилась вторая мысль. Несмотря на наше желание видеть красивый вывод, неизбежный факт то, что две версии MAIN: фрагменты кода, показанные выше функционально идентичны; ассемблер, который является конечной целью кода, не интересует какую версию он получает, за исключением того, что красивая версия будет содержать больше символов, следовательно будет использовать больше дискового пространства и дольше ассемблироваться. Но красивая версия не только генерирует больше кода, но дает больший выходной файл, с гораздо большим количество пустых символов чем минимально необходимо.  Когда вы посмотрите на это с такой стороны, то не трудно будет решить какой подход использовать, не так ли?

То что наконец решило для меня этот вопрос было напоминанием считаться с моей первой заповедью: KISS. Хотя я был довольно горд всеми своими изящными приемчиками для реализации табуляции, я напомнил себе, что перефразируя сенатора Барри Голдватера, элегантность в поисках сложности не является достоинством. Другой мудрый человек однажды написал: "Любой идиот может разработать Роллс-Ройс. Требуется гений, чтобы разработать VW". Так что изящная, дружественная табуляции версия Output в прошлом, и то, что вы видите, это простая компактная VW версия.


Содержание раздела