Разработка компилятора



Оглавление

1 ТЕХНИЧЕСКОЕ ЗАДАНИЕ. 4

2 ОПИСАНИЕ ПРОГРАММЫ. 7

3 ТЕКСТ ПРОГРАММЫ. 17

4 КОНТРОЛЬНЫЙ ПРИМЕР ИСПОЛЬЗОВАНИЯ 47

ЗАКЛЮЧЕНИЕ 64

 

 

1 ТЕХНИЧЕСКОЕ ЗАДАНИЕ.

1.1 Введение

Наименование  программного продукта – «Компилятор».

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

1.2 Основания  для разработки.

Разработка  данного рода программного средства ведется в рамках курсовой работы на основании «Задания на курсовую работу» от 19 марта 2012 года, утвержденного Зав. Кафедрой «Вычислительная техника и автоматизированные системы управления» Е.Г. Шепиловой. Руководитель доцент В.В. Жуков.

1.3 Назначение  разработки.

Разработка  предназначена для компиляции программы  из исходного  кода в код на языке  ассемблера.

1.4 Требования  к программе.

1.4.1 Требования  к функциональным характеристикам  программного продукта.

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

Входной язык должен удовлетворять следующим  требованиям и включать в себя следующие возможности:

- типы  данных (простые типы – логический, целые числа без знака, символы);

- структурные  типы – одномерный массив, символьные  константы;

- Операторы (оператор ввода, оператор вывода, оператор присваивания, условный оператор, оператор цикла с предусловием, оператор цикла ‘do’ по типу Бэйсика).

Способ  реализации лексического и синтаксического  анализаторов остается на усмотрение разработчика.

      1. Требования к надежности.

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

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

      1. Условия эксплуатации.

Программа разработана для эксплуатации в условиях офисных помещений.

      1. Требования к составу и параметрам технических средств.

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

– центральный  процессор – версии Intel ® Pentium III и старше;

– совместимая  видеокарта;

– оперативное  запоминающее устройство емкостью не менее 256 Мб;

– устройство ввода-вывода.

      1. Требования к информационной и программной совместимости.

Программа должна быть спроектирована и разработана  для использования под управлением  операционных систем семейства Microsoft ® Windows версии MS Windows XP и старше.

1.4.6 Требования  к маркировке и упаковке.

Требований  к маркировке и упаковке не предъявляется.

 

1.4.7 Требования  к транспортировке и хранению.

Требований  к транспортировке и хранению не предъявляется.

1.5 Требования  к программной документации.

Программная документация должна включать в себя следующие разделы:

- текст программы;

- описание  программы.

1.6 Технико-экономические  показатели.

Расчет технико-экономических  показателей не требуется.

1.7 Стадии  и этапы разработки.

Разработка  должна быть разделена на три стадии:

- разработка  лексического анализатора;

- разработка  синтаксического анализатора;

- разработка  генератора кода.

1.8 Порядок  контроля и приемки.

Приемка готового продукта осуществляется после  демонстрации его работоспособности. Работоспособность продукта проверяется  путем генерации из исходного  кода заведомо верной программы кода на языке ассемблера, компиляции и  компоновки из кода на языке ассемблера исполняемого файла программы и  проверки ее работоспособности.

 

 

2 ОПИСАНИЕ ПРОГРАММЫ.

2.1 Общие сведения.

Программа написана на языке Паскаль. Графический  интерфейс не реализован. Для запуска  программы необходимо будет запустить  Паскаль и исходный текс программы  для компиляции записать в файл «primer.txt».

2.2 Лексический анализатор.

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

Лексический анализатор (сканер) предназначен для выделения из входного текста лексем – неделимых единиц программы. Лексемами являются имена переменных, процедур и функций, зарезервированные слова, числа, разделители, знаки операций, символьные константы и литералы (строковые константы).

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

Приведем список зарезервированных слов: Program,begin,end,write,read, var,then,for,If,do,while,Repeat,Until,else,to,Boolean,integer,byte,char,array, of,

True,false,not,and,of,or,procedure,loop

Приведем  список однолитерных разделителей (состоящих из одного символа): ‘(‘, ‘)’, ‘+’, ‘-‘, ‘*’, ‘/’, ‘<’, ‘>’, ‘=’, ‘”’, ‘;’, ‘[‘, ‘]’, ‘:’, ‘,’, ‘|’, ‘.’.

Приведем список двулитерных разделителей (состоящих из двух символов): ‘<>’, ‘>=’, ‘<=’, ‘:=’.

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

Выходными данными работы лексического анализатора  является ошибка разбора, выходной поток лексем и токены, содержимое которых формируется на этапе лексического анализа.

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

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

Приведем  правила лексической грамматики для построения автоматов выделения  лексем:

<Лексема>  → <Имя>|<Число>|<Литерал>|<Символьная  константа>|<Однолитерный разделитель>|<Двулитерный разделитель>|<Комментарий>

<Имя>  → <Буква>{<Буква>|<Цифра>}

<Число>  → <Цифра>{<Цифра>}

<Литерал>  →’”’ {<Символ>|(‘”’’”’)}’”’

<Символьная  константа> → ‘<Символ>’

<Однолитерный разделитель> → ‘(‘ | ’)’ | ‘+’ | ‘-‘ | ‘*’ | ‘/’ | ‘<’ | ‘>’ | ‘=’ | ‘”’ | ‘;’ | ‘[‘ | ‘]’ | ‘:’ | ‘,’ | ‘|’ | ‘.’

<Двулитерный разделитель> → ‘<>’ | ‘>=’ | ‘<=’ | ‘:=’ | ‘..’

<Комментарий>  → //{<Символ>}<Конец строки> | ‘/*’{<Символ>}’*/’ | ‘{‘ {<Символ>} ‘}’

<Цифра>  → ‘0’ .. ‘9’

<Буква>  → ‘A’ .. ‘Z’ | ‘a’ .. ‘z’

<Конец  строки> → eoln

Приведем  графы работы автоматов для выделения  имен, чисел, и литералов, а также  автоматы для удаления комментариев

Граф  работы автомата для выделения имен, зарезервированных слов и чисел.

Рис. 1

Граф  работы автомата для выделения литералов.

Рис. 2

Граф  работы автомата, предназначенного для удаления комментариев.

Рис. 3

Граф  работы автомата для выделения простых и сложных разделителей.

Рис. 4

Выходной  поток лексем представляет собой одномерный массив записей, каждая из которых включает в себя имя таблицы, номер в этой таблице.

2.3 Синтаксический анализатор.

Синтаксический  анализатор предназначен для выделения  синтаксических конструкций и правильности их построения. В задачу синтаксического  анализа входят следующие функции:

- найти  и выделить синтаксические конструкции  в тексте исходной программы;

- установить  тип и проверить правильность  каждой синтаксической конструкции.

- управление ходом трансляции  текста исходной программы в  текст результирующей программы.

Синтаксический  анализатор – это основная часть  компилятора.

Синтаксический  анализатор воспринимает выход лексического анализатора и разбирает его  в соответствии с грамматикой  входного языка.

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

Приведем  правила синтаксической грамматики, на основе которой построен синтаксический анализатор:

<программа>  → 'program' I <декларация> <блок операторов> ‘end’,'.'

<декларация > → 'var' ,{ I {‘,’I}’:’ ('integer'|'char'|’byte’|'boolean'|<mas>)

<mas> → 'array' '['C'..'C']' 'of' ('integer'|'char'|'boolean'|’byte’)

<блок операторов> → 'begin' { <оператор>‘;’} ‘end’

<оператор> → <присваивание>|<условный оператор>|<оператор цикла While>|<оператор ввода>|<оператор вывода>|<оператор цикла DO>

<присваивание> → I([E]| ε){‘,’I|[E]| ε}’:=’ E|L|CH

<оператор  цикла while> → ‘while’ L ‘do’ <оператор>

<оператор ввода> → ‘read’ ‘(‘I(|[E] ε)){‘,’ I([E]| ε)}

<оператор вывода> → ‘write’’(’{E|L|<литерал>}’)’

<условный  оператор> → ‘if’ L ‘then’ <оператор> (‘else’ <оператор>| ε)

<оператор цикла do> → ‘do’  {<оператор>} ‘loop’ ‘while|until’ L

L →Т L

ТL → FL {‘or’ TL}

FL → ‘true’ | ’false’ | I [‘[‘E’]’]  | ‘not ‘(‘FL’)’ | ’!’E <предикат сравнения> E’!’

<предикат  сравнения> → ‘=’|’<>’|’>’|’<’|’>=’|’<=’

E → T {‘+’ T | ‘-‘ T}

T → F {‘*’ F | ‘/’ F}

F → I [‘[‘E’]’] | ‘(‘E’)’

Приведем  расшифровку некоторых нетерминальных символов:

E – математическое выражение;

L – логическое выражение;

CH – символьное выражение;

C – число;

I – имя переменной.

На этапе  синтаксического анализа лексемы  воспринимаются как терминальные символы.

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

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

Для каждого  нетерминала грамматики записывается отдельная распознающая процедура. При этом соблюдаются следующие  соглашения:

- Перед  началом работы процедуры текущим  является первый символ анализируемого  понятия.

- В процессе  работы процедура считывается  все символы входной цепочки,  относящиеся к данному нетерминалу  или сообщает об ошибке. Если  правила для данного нетерминала  содержат в правых частях другие  нетерминалы, то процедура обращается  к распознающим процедурам этих  нетерминалов для анализа соответствующих  частей входной цепочки.

- По окончании  работы процедуры текущим становится  первый символ, следующий во входной  последовательности за данной  конструкцией языка.

Список  процедур разбора:

    procedure pr();  

    // процедуры описания заголовка программы и символа конца программы

   

    procedure error(kod:integer);

    //процедура вывода ошибок

    procedure declar();

    //процедура описания блока декларации

    procedure block();

    // процедуры описания раздела блока операторов

    procedure E();

    procedure T();

    procedure F();

    // арифметические выражения

    procedure L();

    procedure TL();

    procedure FL();

    // логические выражения

    procedure block();

    // процедура описания блока операторов

    procedure operator();

    // процедура выбора оператора

    procedure op_if();

    // оператор условия

    procedure op_while();

    // оператор цикла while

    procedure op_read();

    // оператор ввода   

    procedure op_write();

    // оператор вывода

    procedure op_do();

    // оператор цикла do

    Procedure op_pr();

    // оператор присваивания

Синтаксический разбор начинается с вызова процедуры procedure sintax(). Из данной процедуры вызывается процедура разбора целевого символа грамматики pr.

В процедуре  pr() выполняются следующие действия:

- проверяется  наличие ключевого слова ‘program’ и имени программы,

- вызывается  процедура разбора блока переменных declar();

- вызывается  процедура разбора блока кода  block();

- проверяется  наличие ключевого слова ‘end’ и разделителя ‘.’.

Процедура разбора блока переменных declar() выполняет следующие действия:

- проверяет  наличие ключевого слова ‘var’;

- выполняет разбор и заполнение таблицы переменных.

Процедура разбора блока кода block() выполняет следующие функции:

- выполняется  цикл с предусловием, в котором  идентификация оператора и передается управление его процедуре разбора operator:

- если текущим  символом является имя переменной, то вызывается процедура разбора оператора присваивания op_pr(), в противном же случае выполняется оператор множественного выбора:

- если текущим  символом является ключевое слово  ‘if’, то вызывается процедура разбора условного оператора op_if();

- если текущим  символом является ключевое слово  ‘do’, то вызывается процедура разбора оператора цикла op_do ();

- если текущим  символом является ключевое слово  ‘while’, то вызывается процедура разбора цикла с предусловием op_while();

- если текущим  символом является ключевое слово  ‘write’, то вызывается процедура вывода op_write().

- если текущим  символом является ключевое слово  ‘read’, то вызывается процедура ввода op_read().

 

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

2.4 Генерация кода.

Параллельно с синтаксическим анализом производится генерация кода программы на языке  ассемблера. Данный метод называется синтаксически управляемой трансляцией.

Генерация   кода  -   последняя  фаза  трансляции. Результатом  ее   является  ассемблерный  файл (*.asm). В процессе генерации кода могут выполняться некоторые локальные оптимизации, такие как распределение регистров, выбор длинных или коротких переходов, учет стоимости команд при выборе конкретной последовательности команд.

Задача генератора  кода -  построение  эквивалентной  программы на ассемблере по  программе  на  входном языке.  Обычно в  качестве входного для  генератора кода  служит некоторое  промежуточное  представление  программы.

Генерация осуществляется на этапе рекурсивного спуска, когда  разобранному правилу ставится в  соответствие определенная команда        или набор команд ассемблера.

 

 

3 ТЕКСТ ПРОГРАММЫ.

Program kompil;

type

  lek=record

  table:string;

  nomer:integer;

  type_i:string;

  znachenie:string;

  mas:integer;

  end;

var

    f1,f2,f3,f4,f5,f6,f7:text;

    analiz:array [1..1000] of lek;

    x1,x2:string;

    S,i,dlina,n,dl,met,k,nom_analiz:integer;

    alfavit: set of char;

    cifri: set of char;

    razdel: set of char;

    zn_ot:set of char;

    tab_I:array [1..1000] of string;

    bol_tab_i,firstrun:boolean;

    t:string;

    tab_ident:array [1..1000] of string;

    count_ident:integer;

    tab_cifri:array [1..1000] of string;

    count_cifri:integer;

    tab_liter:array [1..1000] of string;

    count_liter:integer;

    tab_hardrazdel:array[1..1000] of string;

    tab_razdel:array[1..1000] of string;

    count_razdel:integer;

    er:real;

    ch1_mas,ch2_mas:integer;

    cur_met:integer;

    g_met:string;

   

procedure leksich;

 

Procedure CMP_tab_liter(var str:string);

var id:boolean;i:integer;

begin

id:=false;

for i:=1 to count_liter do

begin

If tab_liter[i]=x2 then

begin

t:='l';

n:=i;

id:=true;

end;

end;

If id=false then

begin

  tab_liter[count_liter]:=x2;

  t:='l';

  n:=count_liter;

end;

count_liter:=count_liter+1;

end;

 

Procedure CMP_tab_razdel(var str:string);

var id:boolean;i:integer;

begin

id:=false;

for i:=1 to count_razdel do

begin

If tab_razdel[i]=x2 then

begin

t:='s';

n:=i;

id:=true;

end;

end;

If id=false then

begin

  tab_razdel[count_razdel]:=x2;

  t:='s';

  n:=count_razdel;

  count_razdel:=count_razdel+1;

end;

end;

 

Procedure CMP_tab_cifri(var str:string);

var id:boolean;i:integer;

begin

id:=false;

for i:=1 to count_cifri do

begin

If tab_cifri[i]=x2 then

begin

t:='c';

n:=i;

id:=true;

end;

end;

If id=false then

begin

  tab_cifri[count_cifri]:=x2;

  t:='c';

  n:=count_cifri;

  count_cifri:=count_cifri+1;

end;

end;

 

Procedure CMP_tab_I(var str:string);

begin

  t:='';

  n:=0;

  k:=1;

  While tab_i[k]<>'' do

  begin

    If tab_i[k]=x2 then begin t:='k';n:=k; end;

    K:=k+1;

  end;

end;

 

Procedure CMP_tab_hardrazdel(var str:string);

begin

  t:='';

  n:=0;

  k:=1;

  While tab_hardrazdel[k]<>'' do

  begin

    If tab_hardrazdel[k]=str then begin t:='h';n:=k; end;

    K:=k+1;

  end;

end;

 

Procedure CMP_tad_ident(var str:string);

var id:boolean;i:integer;

begin

id:=false;

for i:=1 to count_ident do

begin

If tab_ident[i]=x2 then

begin

t:='i';

n:=i;

id:=true;

end;

end;

If id=false then

begin

  tab_ident[count_ident]:=x2;

  t:='i';

  n:=count_ident;

  count_ident:=count_ident+1;

end;

end;

 

begin

Repeat

readln(f2,x1);

tab_I[k]:=x1;

k:=k+1;

until eof(f2);

K:=1;

Repeat

readln(f3,x1);

tab_hardrazdel[k]:=x1;

k:=k+1;

until eof(f3);

s:=0;

nom_analiz:=1;

Repeat

readln(f1,x1);

dlina:=Length(x1);

For i:=1 to dlina+2 do

begin

case s of

0: Begin If (x1[i] in alfavit) then Begin S:=11; x2:=x2+x1[i] end else begin If (x1[i] in cifri)  then Begin S:=13; x2:=x2+x1[i] end else S:=0;end;

   If x1[i]='''' then begin S:=21;dl:=1;end else if (x1[i] in razdel ) and (x1[i+1]<>'/') and (x1[i+1]<>'*') then begin S:=41; x2:=x2+x1[i];i:=i-1; end;

   If x1[i]='{' then begin S:=31;x2:=x2+x1[i];met:=Length(x2);dl:=dl+1; end else

begin

  if x1[i]='/' then begin S:=33;x2:=x2+x1[i] end;// else x2:=x2+x1[i];

  If dlina=i then begin S:=32;i:=i-1; end;

   end;

   end;

 

11: Begin If (x1[i] in alfavit) or (x1[i] in cifri) then x2:=x2+x1[i] else begin S:=12;i:=i-1; end; If i=dlina then begin S:=12;end; end;

12: Begin CMP_tab_I(x2); If (n=0) and (x2[1] in alfavit) then CMP_tad_ident(x2) else if x2[1] in cifri then cmp_tab_cifri(x2);writeln(f4,' ',t,' ',n);analiz[nom_analiz].table:=t;analiz[nom_analiz].nomer:=n;nom_analiz:=nom_analiz+1;S:=0;delete(x2,1,dlina);i:=i-1; end;

13: Begin If (x1[i] in cifri) then x2:=x2+x1[i] else begin S:=12;i:=i-1; end;; If i=dlina then begin i:=i-1;S:=12;end;end;

 

 

21:begin If x1[i]='''' then begin S:=23; end else begin x2:=x2+x1[i];dl:=dl+1;end; end;

22:begin cmp_tab_liter(x2); writeln(f4,' ',t,' ',n);analiz[nom_analiz].table:=t;analiz[nom_analiz].nomer:=n;nom_analiz:=nom_analiz+1;i:=i-1;delete(x2,1,dl);S:=0;dl:=1;end;

23:begin If x1[i]='''' then begin x2:=x2+x1[i];dl:=dl+1;S:=21;end else begin S:=22;i:=i-1;end;  end;

 

31:begin If x1[i]='}' then begin S:=32;delete(x2,met,dl)end else begin x2:=x2+x1[i];dl:=dl+1; end; If (eof(f1)=true) and (dlina=i) then begin S:=32;i:=i-1;end; end;

32:begin If dlina<>i then i:=i-1;if x2<>'' then begin writeln(f4);delete(x2,1,dlina);S:=0;dl:=0;met:=0;end else S:=0;end;

33:begin If x1[i]='*' then begin S:=34; met:=Length(x2);dl:=dl+2;x2:=x2+x1[i]; end else begin x2:=x2+x1[i]; S:=0; end; if x1[i]='/' then begin S:=36;met:=length(x2)-1;end; If (eof(f1)=true) and (dlina=i) then begin S:=32;i:=i-1;end;end;

34:begin If x1[i]='*' then begin S:=35; x2:=x2+x1[i];dl:=dl+1; end else begin x2:=x2+x1[i];dl:=dl+1;end;If (eof(f1)=true) and (dlina=i) then begin S:=32;i:=i-1;end;end;

35:begin If x1[i]='/' then begin S:=32;delete(x2,met,dl) end else begin x2:=x2+x1[i];S:=34;dl:=dl+1;end;If (eof(f1)=true) and (dlina=i) then begin S:=32;i:=i-1;end;end;

36:begin If dlina=i then begin S:=32;i:=i-1;delete(x2,met,2)end; end;

 

41:begin n:=0;t:=''; If (x1[i+1] in razdel) then begin x2:=x2+x1[i+1]; cmp_tab_hardrazdel(x2);end;  If n<>0 then begin S:=42;i:=i+1; end else begin S:=42;delete(x2,1,dlina);x2:=x2+x1[i]; cmp_tab_razdel(x2);end;  If i=dlina then begin S:=42;end; end;

42:begin writeln(f4,' ',t,' ',n);analiz[nom_analiz].table:=t;analiz[nom_analiz].nomer:=n;nom_analiz:=nom_analiz+1;S:=0;delete(x2,1,dlina);i:=i-1;end;

end;

end;

Until eof(f1);

end;

 

procedure sintax;

   var current_analiz:integer;

       type_virag: array[1..10] of string;

       cur_vir:integer;

       cur_stroka:integer;

   procedure block;forward;

   procedure declar;forward;

   procedure mass;forward;

  

   procedure AddProcedures;

begin

  writeln(F6,'R_B proc near');

  writeln(F6,'CMP BUFS,''t''');

  writeln(F6,'JNZ FN');

  writeln(F6,'PUSH 1 ; TRUE');

  writeln(F6,'JMP PBEnd');

  writeln(F6,'FN: CMP BUFS, ''f''');

  writeln(F6,'JNZ EndKode1');

  writeln(F6,'EndKode1:');

  writeln(F6,'JMP EndKode');

  writeln(F6,'PUSH 0');

  writeln(F6,'PBEnd:');

  writeln(F6,'RET');

  writeln(F6,'ENDP');

  writeln(F6,'');

 

  writeln(F6,'R_Ch proc near');

  writeln(F6,'mov bx,0');

  writeln(F6,'M:');

  writeln(F6,'mov ah,08h');

  writeln(F6,'int 21h');

  writeln(F6,'mov dl,al');

  writeln(F6,'mov ah,02h');

  writeln(F6,'int 21h');

  writeln(F6,'cmp al,'' ''');

  writeln(F6,'jz M');

  writeln(F6,'cmp al,13');

  writeln(F6,'jz M');

  writeln(F6,'mov BUFS[bx],al');

  writeln(F6,'M1:');

  writeln(F6,'mov ah,08h');

  writeln(F6,'int 21h');

  writeln(F6,'mov dl,al');

  writeln(F6,'mov ah,02h');

  writeln(F6,'int 21h');

  writeln(F6,'cmp al,'' ''');

  writeln(F6,'jz M2');

  writeln(F6,'cmp al,13');

  writeln(F6,'jz M2');

  writeln(F6,'inc bx');

  writeln(F6,'mov BUFS[bx],al');    

  writeln(F6,'jmp M1');

  writeln(F6,'M2:');

  writeln(F6,'mov cx,bx');  

  writeln(F6,'mov al,13');

  writeln(F6,'mov ah,02h');

  writeln(F6,'int 21h');

  writeln(F6,'ret');

  writeln(F6,'ENDP');

  writeln(F6,'');

 

  writeln(F6,'PR_Int proc near');

  writeln(F6,'push bx');

  writeln(F6,'push cx');

  writeln(F6,'push dx');

  writeln(F6,'test ax,ax');

  writeln(F6,'push -1');

  writeln(F6,'mov cx,10');

  writeln(F6,'wrem:');

  writeln(F6,'xor dx,dx');

  writeln(F6,'div cx');

  writeln(F6,'push dx');

  writeln(F6,'test ax,ax');

  writeln(F6,'jnz wrem');

  writeln(F6,'mov ah,02h');

  writeln(F6,'orem:');

  writeln(F6,'pop dx');

  writeln(F6,'test dx,dx');

  writeln(F6,'js output_int_exit');

  writeln(F6,'add dl,''0''');

  writeln(F6,'int 21h');

  writeln(F6,'jmp orem');

  writeln(F6,'output_int_exit:');

  writeln(F6,'pop dx');

  writeln(F6,'pop cx');

  writeln(F6,'pop bx');

  writeln(F6,'ret');

  writeln(F6,'ENDP');

  writeln(F6,'');

 

  writeln(F6,'R_Int proc near');

  writeln(F6,'push bx');

  writeln(F6,'push cx');

  writeln(F6,'push dx');

  writeln(F6,'mov bx,0');

  writeln(F6,'mov ax,0');

  writeln(F6,'inc cx');

  writeln(F6,'mov bufs3,cx'); 

  writeln(F6,'m_start:');

  writeln(F6,'mov cx,10');

  writeln(F6,'mul cx');

  writeln(F6,'mov dx,0');

  writeln(F6,'push ax');

  writeln(F6,'mov dl,BUFS[bx]');

  writeln(F6,'mov cx,dx');

  writeln(F6,'sub dx,30h');

  writeln(F6,'pop ax');

  writeln(F6,'add ax,dx');

  writeln(F6,'inc bx');

  writeln(F6,'mov cx,bufs3');

  writeln(F6,'cmp cx,bx');

  writeln(F6,'jnz m_start');

  writeln(F6,'m_exit:');

  writeln(F6,'pop bx');

  writeln(F6,'pop cx');

  writeln(F6,'pop dx');

  writeln(F6,'ret');

  writeln(F6,'ENDP');

 

  writeln(F6,'');

  writeln(F6,'outline proc');

  writeln(F6,'push dx');

  writeln(F6,'mov ah,02h');

  writeln(F6,'mov dl,0dh');

  writeln(F6,'int 21h');

  writeln(F6,'mov dl,0Ah');

  writeln(F6,'int 21h');

  writeln(F6,'pop dx');

  writeln(F6,'ret');

  writeln(F6,'outline endp');

 

  writeln(F6,'');

  writeln(F6,'output_logic proc');

  writeln(F6,'push dx');

  writeln(F6,'test ax,ax');

  writeln(F6,'jz  output_logic_false');

  writeln(F6,'mov dx, offset $logic_true');

  writeln(F6,'jmp output_logic_end');

  writeln(F6,'output_logic_false:');

  writeln(F6,'mov dx, offset $logic_false');

  writeln(F6,'output_logic_end:');

  writeln(F6,'mov ah,9h');

  writeln(F6,'int 21h');

  writeln(F6,'pop dx');

  writeln(F6,'ret');

  writeln(F6,'output_logic    endp');

  writeln(F6,'');

end;

 

  

   procedure error(kod:integer);

    begin

     //cur_stroka:=cur_stroka+1;

    case kod of

      1:Writeln('Ожидалось слово Program','  строка-',cur_stroka);

      2:writeln('Ожидался идентификатор','  строка-',cur_stroka);

      3:writeln('ожидалась  ";"','  строка-',cur_stroka);

      4:writeln('Ожидалось  end','  строка-',cur_stroka);

      5:writeln('Ожидалось  "."','  строка-',cur_stroka);

      6:writeln('Ожидалось  var','  строка-',cur_stroka);

      7:writeln('Ожидалось  ","','  строка-',cur_stroka);

      8:writeln('Ожидалось  ":"','  строка-',cur_stroka);

      9:writeln('Ожидалось begin','  строка-',cur_stroka);

      10:writeln('Не известный тип данных','  строка-',cur_stroka);

      11:writeln('Неверное логическое  выражение','  строка-',cur_stroka);

      12:writeln('Ожидалось  "]"','  строка-',cur_stroka);

      13:writeln('Ожидалось  ")"','  строка-',cur_stroka);

      14:writeln('неверный знак  сравнения','  строка-',cur_stroka);

      15:writeln('Ожидалось  "!"','  строка-',cur_stroka);

      16:writeln('Неверное арифметическое  выражение','  строка-',cur_stroka);

      17:writeln('Переменная  не оъявлена','  строка-',cur_stroka);

      18:writeln('Ожидалось  :=','  строка-',cur_stroka);

      19:writeln('Ожидалось then','  строка-',cur_stroka);

      20:writeln('Ожидалось do','  строка-',cur_stroka);

      21:writeln('Ожидалось "("','  строка-',cur_stroka);

      22:writeln('Ожидалось  "["','  строка-',cur_stroka);

      23:writeln('Ожидалось  число','  строка-',cur_stroka);

      24:writeln('Ожидалось  ".."','  строка-',cur_stroka);

      25:writeln('Ожидалось  of','  строка-',cur_stroka);

Разработка компилятора