Содержание материала

ВВОД/ВЫВОД

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

Современное соглашение, установленное в C и продолженное в Ada и Modula-2, состоит в том, чтобы вывести I/O операторы из самого языка и просто включить их в библиотеку подпрограмм. Это было бы прекрасно, за исключением того, что мы пока не имеем никаких средств поддержки подпрограмм. В любом случае, с этим подходом вы столкнетесь с проблемой переменной длины списка параметров. В Паскале I/O операторы встроены в язык, поэтому это единственные операторы, для которых список параметров может иметь переменное число элементов. В C мы примиряемся с клуджами типа scanf и printf и должны передавать количество параметров в вызываемую процедуру. В Ada и Modula-2 мы должны использовать неудобный (и медленный!) способ отдельного вызова для каждого аргумента.

Так что я думаю, что предпочитаю Паскалевский подход встраивания подпрограмм ввода/вывода, даже если мы не нуждаемся в этом.

Как обычно, для этого нам нужны еще несколько подпрограмм генерации кода. Они, оказывается, самые простые из всех, потому что все, что мы делаем это вызываем библиотечные процедуры для выполнения работы.

Code:

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

{ Read Variable to Primary Register }

procedure ReadVar;

begin

   EmitLn('BSR READ');

   Store(Value);

end;

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

{ Write Variable from Primary Register }

procedure WriteVar;

begin

   EmitLn('BSR WRITE');

end;

 

 

Идея состоит в том, что READ загружает значение из входного потока в D0, а WRITE выводит его оттуда.

Эти две процедуры представляют собой нашу первую встречу с потребностью в библиотечных процедурах... компонентах Run Time Library (RTL). Конечно кто-то (а именно мы) должен написать эти подпрограммы, но они не являются непосредственно частью компилятора. Я даже не буду беспокоиться о том, чтобы показать здесь эти подпрограммы, так как они очевидно очень ОС-зависимы. Я просто скажу, что для SK*DOS они особенно просты... почти тривиальны. Одна из причин, по которым я не буду показывать их здесь в том, что вы можете добавлять новые виды возможностей, например приглашение в READ или возможность пользователю повторить ошибочный ввод.

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

Так как нам теперь нужно загружать ее, мы должны добавить ее загрузку в процедуру Header:

Code:

{ Write Header Info }

procedure Header;

begin

   WriteLn('WARMST', TAB, 'EQU $A01E');

   EmitLn('LIB TINYLIB');

end;

 
 

 

Она возьмет на себя эту часть работы. Теперь нам также необходимо распознавать команды ввода и вывода. Мы можем сделать это добавив еще два ключевых слова в наш список:

Code:

{ Definition of Keywords and Token Types }

const NKW =   11;

      NKW1 = 12;

const KWlist: array[1..NKW] of Symbol =

              ('IF', 'ELSE', 'ENDIF', 'WHILE', 'ENDWHILE',

               'READ',    'WRITE',    'VAR',    'BEGIN',   'END',

'PROGRAM');

const KWcode: string[NKW1] = 'xileweRWvbep';

 

 

 

(Обратите внимание, что здесь я использую кода в верхнем регистре чтобы избежать конфликта с 'w' из WHILE.)

Затем нам нужны процедуры для обработки оператора ввода/вывода и его списка параметров:

Code:

{ Process a Read Statement }

procedure DoRead;

begin

   Match('(');

   GetName;

   ReadVar;

   while Look = ',' do begin

      Match(',');

      GetName;

      ReadVar;

   end;

   Match(')');

end;

 

{ Process a Write Statement }

procedure DoWrite;

begin

   Match('(');

   Expression;

   WriteVar;

   while Look = ',' do begin

      Match(',');

      Expression;

      WriteVar;

   end;

   Match(')');

end;

 

 

 

Наконец, мы должны расширить процедуру Block для поддержки новых типов операторов:

 

Code:

{ Parse and Translate a Block of Statements }

procedure Block;

begin

   Scan;

   while not(Token in ['e', 'l']) do begin

      case Token of

       'i': DoIf;

       'w': DoWhile;

       'R': DoRead;

       'W': DoWrite;

      else Assignment;

      end;

      Scan;

   end;

end;

 

 

 

На этом все. Теперь у нас есть язык!

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить