Разработка однопроходного компилятора

 

Оглавление


Введение

Расчёт варианта задания

Разработка контрольного примера

Описание используемых директив и команд ассемблера

Выбор варианта построения ассемблера, описание алгоритмов и таблиц

Листинг программы

Алгоритм работы программной реализации разрабатываемого компилятора

Заключение



Введение


Основной целью курсовой работы является создание и изучение объектного файла. Создаваемый объектный файл должен восприниматься линковщиком и преобразовываться в исполняемый файл (COM или EXE). Перевод исходной программы в её объектное представление осуществляет транслятор, поэтому его программная реализация также является целью курсовой работы.

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

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

Транслятор обычно выполняет также диагностику ошибок, формирует словари идентификаторов, выдаёт для печати тексты программы и т. д.

Язык, на котором представлена входная программа, называется исходным языком, а сама программа - исходным кодом. Выходной язык называется целевым языком или объектным кодом.

Трансляторы подразделяют:

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

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

Однопроходной. Формирует объектный модуль за один последовательный просмотр исходной программы.

Многопроходной. Формирует объектный модуль за несколько просмотров исходной программы.

Оптимизирующий. Выполняет оптимизацию кода в создаваемом объектном модуле.

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

Обратный. Для программы в машинном коде выдаёт эквивалентную программу на каком-либо языке программирования.

Процесс компиляции состоит из двух основных этапов ? анализа и синтеза (рис. 1).

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

На этапе синтеза из внутреннего представления программы и информации из таблицы идентификаторов, получается результирующая объектная программа.

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

Лексический анализ. Эту часть компилятора выполняет сканер, который читает литеры программы (символы) на исходном языке и строит из них слова (лексемы) исходного языка. На входе сканера (лексического анализатора) текст исходной программы, выходная информация передаётся для дальнейшей обработки на этап синтаксического разбора.

Синтаксический разбор ? это основная часть компилятора на этапе анализа. Здесь в тексте исходной программы выделяются синтаксические конструкции. Кроме того, проверяется синтаксическая правильность программы.

Рис. 1. Функции основных фаз компиляции:


Семантический анализ ? это часть компилятора, проверяющая часть текста исходной программы с точки зрения семантики входного языка.

Подготовка к генерации кода ? на этой фазе компилятор выполняет предварительные действия, непосредственно связанные с синтезом текста результирующей программы: идентификация элементов языка, распределение памяти и т.п. Эта подготовка ещё не ведёт к порождению текста на выходном языке.

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

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

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

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

Другой метод реализации - когда программа исполняется с помощью интерпретатора вообще без трансляции. Интерпретатор программно моделирует машину, цикл выборки-исполнения которой работает с командами на языках высокого уровня, а не с машинными командами. Такое программное моделирование создаёт виртуальную машину, реализующую язык. Этот подход называется чистой интерпретацией. Чистая интерпретация применяется как правило для языков с простой структурой (например, АПЛ или Лисп). Интерпретаторы командной строки обрабатывают команды в скриптах в UNIX или в пакетных файлах (.bat) в MS-DOS также как правило, в режиме чистой интерпретации.

Достоинство чистого интерпретатора: отсутствие промежуточных действий для трансляции упрощает реализацию интерпретатора и делает его удобнее в использовании, в том числе в диалоговом режиме. Недостаток - интерпретатор должен быть в наличии на целевой машине, где должна исполняться программа. А свойство чистого интерпретатора, что ошибки в интерпретируемой программе обнаруживаются только при попытке выполнения команды (или строки) с ошибкой, можно признать как недостатком, так и достоинством.

Существуют компромиссные между компиляцией и чистой интерпретацией варианты реализации языков программирования, когда интерпретатор перед исполнением программы транслирует её на промежуточный язык (например, в байт-код или p-код), более удобный для интерпретации (то есть речь идёт об интерпретаторе со встроенным транслятором). Такой метод называется смешанной реализацией. Примером смешанной реализации языка может служить Perl. Этот подход сочетает как достоинства компилятора и интерпретатора (большая скорость исполнения и удобство использования), так и недостатки (для трансляции и хранения программы на промежуточном языке требуются дополнительные ресурсы; для исполнения программы на целевой машине должен быть представлен интерпретатор). Также, как и в случае компилятора, смешанная реализация требует, чтобы перед исполнением исходный код не содержал ошибок (лексических, синтаксических и семантических).

По мере увеличения ресурсов компьютеров и расширения гетерогенных сетей (в том числе Интернета), связывающих компьютеры разных типов и архитектур, выделился новый вид интерпретации, при котором исходный (или промежуточный) код компилируется в машинный код непосредственно во время исполнения, «на лету». Уже скомпилированные участки кода кэшируются, чтобы при повторном обращении к ним они сразу получали управление, без перекомпиляции. Этот подход получил название динамической компиляции.

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

Этот метод хорошо подходит для веб-приложений. Соответственно, динамическая компиляция появилась и поддерживается в той или иной мере в реализациях Java,.NET Framework, Perl, Python.


Расчёт варианта задания


Расчёт задания для каждой группы команд идёт по формуле:


(1)


Где: NG - последние две цифры учебной группы студента, NS - номер студента в списке группы, KV - количество вариантов в соответствующей группе команд.

Тогда, получаем:

·((83+9) mod 12) = 8;

·((83+9) mod 15) = 2;

·((83+9) mod 10) = 2;

·((83+9) mod 8) = 4;

·((83+9) mod 6) = 2.

В результате базовый набор команд: NOP, JG, ADD, ROR, DEC. Так же нам понадобятся команды MOV, INT.


Разработка контрольного примера


.286

datasegment

a1dw 1001h

a2 dw 100hdw 101hdw 4c00hendssegmentds:data, cs:code:ax,a1ax,101ha3ax,5h@2

nop

@2:ax,c21hends

end main

Данный контрольный пример без ошибок компилируется и линкуется стандартными компиляторами и линковщиками.


Описание используемых директив и команд ассемблера

транслятор ассемблер компилятор

-r8, r16, r32 - операнд в одном из регистров размером байт, слово или двойное слово;

-m8, m16, m32 - операнд в памяти размером байт, слово или двойное слово;

-i8, i16, i32 - непосредственный операнд размером байт, слово или двойное слово;

-a8, a16, a32 - относительный адрес (смещение) в сегменте кода;


Выбор варианта построения ассемблера, описание алгоритмов и таблиц


MOV:

Пересылает один байт или одно слово между регистрами или между регистром и памятью, а также передаёт непосредственное значение в регистр или в память. Команда MOV не может передавать данные между двумя адресами памяти (для этой цели служит команда MOVS).



ADD:



DEC:



ROR:



JG:



NOP:


INT:



Листинг программы

Unit1;, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls, Grids, ExtCtrls, ComCtrls, Menus,math;

type= record //запись - директива:string;:string;:string;:string;:boolean; //признак того, что директива описана и распознаётся

end;= record //запись - оператор:string;:string;:string;:string;:string;:string;:boolean; //признак того что оператор описан и распознаётся;= record:boolean; //наличие сегмента кода:boolean; //наличие сегмента данных

end;

TForm1 = class(TForm): TPageControl;: TTabSheet;: TTabSheet;: TLabel;: TMemo;: TStringGrid;: TMemo;: TMemo;: TMemo;: TMemo;: TMainMenu;: TMenuItem;: TMenuItem;: TButton;: TButton;: TStringGrid;: TScrollBar;: TMemo;: TLabel;: TLabel;: TLabel;: TLabel;: TLabel;: TLabel;: TLabel;: TStringGrid;: TGroupBox;: TMemo;: TMemo;: TLabel;: TLabel;: TMenuItem;: TButton;: TEdit;: TMenuItem;: TButton;

OpenDialog1: TOpenDialog;: TMemo;: TSaveDialog;

procedure NewProgramButtonClick(Sender: TObject); //Подготовка к работеTranslAndSaveMenuClick(Sender: TObject);//Моментальная трансляцияClearCodeButtonClick(Sender: TObject);//Очистка кодаCreateObjFileClick(Sender: TObject);//Вычисление сегментов данныхexeAllClick(Sender: TObject);//Трансляция кодаExit1Click(Sender: TObject);//Закрыть приложениеFormCreate(Sender: TObject);

//ПроверкиGerArgType(arg:string):string;//получение типа аргументаIsVar(arg:string):boolean;//переменнаяisImm(arg:string):boolean; //числоisData(str:string):boolean;//[si+n]isReg(arg:string):boolean; //регистр 16

//рассчет мнемокодаinsRegMul(mem:string; arg:string; koef:integer):string;insReg(mem:string; arg:string):string;InvertBytes(s:string):string;ImmToHex(imm:string;len:string):string;cnvData(dat:string):string;AddControlByte(s:string):string;HexByteToByte(s:string):byte;CharToByte(C:char):byte;NexStrToStr(nexstr:string):string;IntToHexStr(int:integer):string;AnalysisCommand (comstr:string):command;ComNext:string;ComRead:string;ComIs:string;DeleteSpace(str:string):string;DecompositeCommand(comstr:string):Command;ModifyMarkAdress:string;AddLinksInMarkers;MarkTableWrite(Mname,LBytepos,CBytepos,Strpos:string);MarksLinksTableWrite(Mname,LBytepos:string);ComExe;AnalysisDirective(DrcStr:string):directive;DecompositeDirective(DrcStr:string):directive;DataTableWrite(Varible:string; Len:string;Code:string);GetVarCodeByName(name:string):string;

//управление прокруткойSlideDown;SlideUp;ScrollBar1Change(Sender: TObject);

//Загрузка и сохранениеCodeDblClick(Sender: TObject);SaveMenuClick(Sender: TObject);WriteHexStr(ss:string);//запись строки в файл

//перевод из Ansi в hexStrToHexStr(str:string):string;StrDelSpaseHex(s:string):string;

{ Private declarations }

{ Public declarations };

//Глобальные переменные

var

Form1: TForm1;

ThisProgram:Prog; //параметр программы (контроль за наличием сегментов)

Reg16,Reg8:arrayofstring; //динамический список имен регистров (нумерация для мнемокодов)

ComReadPos:integer; //cчетчик команд

ComBytePos:integer; //cчетчик байтов

DataBytes:integer; //для формирования сегмента данных

ErrorControl:string; //для хранения ошибки

VariableAdr:string; //для формирования таблицы ссылок

RegLen:string; //хранение размера регистра при анализировании команды

VarLen:string; //хранение размера переменной при анализировании команды

VarCode:string; //хранение адреса переменной при анализировании команды

FileSave:file of byte;//файл с кодом:textfile;//Выходной файл

{$R *.dfm}

//добавить к мнемокоду номер рeгистра*k, указанного в аргументе: ('A0' + 'cx' = 'A1')

function TForm1.insRegMul(mem:string; arg:string; koef:integer):string;

var pos:integer; intcode:integer;(arg);:=0;:=ord(NexStrToStr(mem)[1]); //16-ый код - строка (пример: 'A0') переводится в целое число

//получение номера регистра:(RegLen='R16') then for pos:=0 to length(Reg16) do if arg=Reg16[pos] then break;(RegLen='R8') then for pos:=0 to length(Reg8) do if arg=Reg8[pos] then break;:=intcode+pos*koef; //добавление позиции регистра к мнемокоду

mem:=IntToHex(intcode,2); //перевод обратно в 16-ый код - строку

insRegMul:=mem;

end;

//добавить к мнемокоду номер рeгистра, указанного в аргументе: ('A0' + 'cx' = 'A1')

function TForm1.insReg(mem:string; arg:string):string;

var pos:integer; intcode:integer;(arg);:=0;:=ord(NexStrToStr(mem)[1]); //16-ый код - строка (пример: 'A0') переводится в целое число

//получение номера регистра:(RegLen='R16') then for pos:=0 to length(Reg16) do if arg=Reg16[pos] then break;(RegLen='R8') then for pos:=0 to length(Reg8) do if arg=Reg8[pos] then break;.Text:=edit1.Text+'$pos='+inttostr(pos);:=intcode+pos; //добавление позиции регистра к мнемокоду

mem:=IntToHex(intcode,2); //перевод обратно в 16-ый код - строку

insReg:=mem;;TForm1.StrToHexStr(str:string):string; //перевод текста в строку в код 16 с/cpos:integer; hexstr:string;:='';pos:=1 to length(str) do hexstr:=hexstr+IntToHex(ord(str[pos]),2);:=hexstr;;TForm1.SlideDown;.Perform(WM_VSCROLL, SB_LINEDOWN, 1);.Perform(WM_VSCROLL, SB_LINEDOWN, 1);.Perform(WM_VSCROLL, SB_LINEDOWN, 1);;TForm1.SlideUp;.Perform(WM_VSCROLL, SB_LINEUP, 1);.Perform(WM_VSCROLL, SB_LINEUP, 1);.Perform(WM_VSCROLL, SB_LINEUP, 1);;TForm1.TranslAndSaveMenuClick(Sender: TObject);

ExeAll.Click; //транслирование всей программы

CreateObjFile.Click; //Формирование объектного файла

SaveMenu.Click; //сохранение

end;

functionTForm1.GetVarCodeByName(name:string):string; //из таблицы переменных взять код переменной по имени

var row:integer; adrs:string;:='';row:=1 to Varibles.RowCount-1 do if Varibles.Cells[0,row]=name then begin GetVarCodeByName:=Varibles.Cells[1,row];VarLen:=Varibles.Cells[3,row];exit;end;:='<Необъяв. перемен.>';

end;TForm1.DataTableWrite(Varible:string; Len:string;Code:string); //запись в таблицу переменных:integer;

begin

//ComBytePos глобальная переменная - счетчик байтов для записи переменных в сегмент данных

Varibles.RowCount:=Varibles.RowCount+1;:=Varibles.RowCount-1;.Cells[0,row]:=Varible;.Cells[1,row]:=IntToHex(DataBytes,4);.Cells[2,row]:=Code;Len='db' then Begin:=DataBytes+1;.Cells[3,row]:='V8';;Len='dw' then Begin:=DataBytes+2;.Cells[3,row]:='V16';;;TForm1.DecompositeDirective(DrcStr:string):directive;:integer;

//начальные значения.part1:='';.part2:='';.part3:='';

//установка ограничения для строки-директивы

DrcStr:=DrcStr+' ';

//1)извлечение первой части:pos:=1 to length(DrcStr) do if DrcStr[pos]=' ' then begin.part1:=copy(DrcStr,1,pos-1);(DrcStr,1,pos);;;

//2)извлечение второй части:pos:=1 to length(DrcStr) do if DrcStr[pos]=' ' then begin.part2:=copy(DrcStr,1,pos-1);(DrcStr,1,pos);;;

//3)извлечение третьей части:pos:=1 to length(DrcStr) do if DrcStr[pos]=' ' then begin.part3:=copy(DrcStr,1,pos-1);(DrcStr,1,pos);;;;TForm1.AnalysisDirective(DrcStr:string):directive;drc:directive;:=DecompositeDirective(DrcStr);drc do BEGIN:=false;

//dd,dw(part1<>'') and ((part2='dw')or(part2='db')) and isImm(part3) then begin:=ImmToHex(part3,part2);(part1,part2,MashCode);:=true;

end;

//dd,dw без имени переменной

if ((part1='dd')or(part1='dw')) and isImm(part2) then begin:=ImmToHex(part2,part1);('',part1,MashCode);:=true;;(part1='masm') then exist:=true;(part1='.code') then exist:=true;(part1='.data') then exist:=true;(part1='.model') and (part2='small')then exist:=true;(part1='.stack') then exist:=true;(part1='.286') then exist:=true;(part1='end') then exist:=true;(part1='data') and (part2='segment') then exist:=true;(part1='data') and (part2='ends') then exist:=true;(part1='code') and (part2='segment') then exist:=true;(part1='code') and (part2='ends') then exist:=true;(part1='assume') then exist:=true;(part1='ends') then exist:=true;(part1='end') and (part2='main') then exist:=true;;:=drc;;TForm1.ComExe; //транслирование строки программы:command; //команда записанная в специальной записи - команда

drc:directive; //директива записанная в специальной записи - директива

comstr:string; //команда в текстовом виде

pos:integer;

begin

//добавление строк в байтовый счетчик, кодовую часть и часть данных

MashCode.Lines.Add('');.Lines.Add('');

//проверка на строку-пустоту или строку - сплошной комментарий:

//..если встречается такая строка, то выход без обработки

comstr:=ComRead;

//если строка в коде программы является полностью комментарием:

if length(comstr)>=1 then begin:=1; while (comstr[pos]=' ')and(pos<length(comstr)) do inc(pos);comstr[pos]=';' then exit;;

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

if comstr='' then exit;.Lines[ComReadPos]:=IntToHex(ComBytePos,4);

//обработка команд - операторов

com:=AnalysisCommand(comstr);

MashCode.Lines[ComReadPos]:=com.MashCode;com.ByteLen<>'' then ComBytePos:=ComBytePos + strtoint(com.ByteLen);

//обработка команд - директив:=AnalysisDirective(ComRead);

//MashData.Lines[ComReadPos]:=drc.MashCode;

//----------------------------------------------------------------------------->

//выявление ошибок в синтаксисе:

ifcom.MashCode<>'' thencom.exist:=true; //если есть машинный код то оператор распознан

if (notcom.exist) and (notdrc.exist) //если ни директива, ни оператор не распознаны то:

then MashCode.Lines[ComReadPos]:='<Неизв. ком.>';

//анализ сообщений об ошибках:ErrorControl<>'' then MashCode.Lines[ComReadPos]:=ErrorControl;:=''; //стирание сообщений об ошибках

//----------------------------------------------------------------------------->;TForm1.MarksLinksTableWrite(Mname,LBytepos:string);:integer;

begin

//поиск введенной метки среди существующих

row:=1; while (row<=markslinks.RowCount-1) do beginmarkslinks.Cells[0,row]=Mname then begin

//если поиск успешен - то вывод ошибки (повторное описание ссылки метки)

ErrorControl:='<Переопр. метки>';;;(row);;

//если вносимой ссылки нет - то внести её

markslinks.RowCount:=row+1; //row указывает на конец таблицы

if Mname <>'' then markslinks.Cells[0,row]:=Mname;LBytepos<>'' then markslinks.Cells[1,row]:=LBytepos;.FixedRows:=1; //выделить заголовок таблицы

end;

procedure TForm1.MarkTableWrite(Mname,LBytepos,CBytepos,Strpos:string);row:integer;

//добавление ссылки метки:<>'' thenbegin

//добавление ко всем меткам ссылок

row:=1; while (row<=marks.RowCount-1) do beginmarks.Cells[0,row]=Mname then if LBytepos<>'' then.Cells[1,row]:=LBytepos;(row);;

end;

//добавление оператора, использующего метку

if CBytepos<>'' then begin.RowCount:=marks.RowCount+1;.FixedRows:=1;:=marks.RowCount-1;Mname <>'' then marks.Cells[0,row]:=Mname;CBytepos<>'' then marks.Cells[2,row]:=CBytepos;Strpos <>'' then marks.Cells[3,row]:=Strpos;;;;TForm1.ModifyMarkAdress:string; //расчет смещений и добавление их в сегмент кодаrow,l:integer;row:=1 to marks.RowCount-1 do beginMashCode.Lines[strtoint(marks.Cells[3,row])]='E8' then l:=4l:=2;(marks.Cells[0,row]<>'')and(marks.Cells[2,row]<>'') then begin(strtoint(marks.Cells[1,row])<strtoint(marks.Cells[2,row])) then begin.Lines[strtoint(marks.Cells[3,row])]:=.Lines[strtoint(marks.Cells[3,row])]+(IntToHex(256-(strtoint(marks.Cells[2,row])-strtoint (marks.Cells[1,row])),l)); end.Lines[strtoint(marks.Cells[3,row])]:=.Lines[strtoint(marks.Cells[3,row])]+(IntToHex(strtoint(marks.Cells[1,row])-strtoint(marks.Cells[2,row]),l));;;TForm1.AddLinksInMarkers; //добавление ссылок в таблицу метокrow:integer;:=1; while row<=markslinks.RowCount do begin(markslinks.Cells[0,row],markslinks.Cells[1,row],'','');(row);;;TForm1.IntToHexStr(int:integer):string; //преобразование целого числа в строку - 16-ую запись этого числаres:string;:=IntToHex(int,2);length(res)>2 do delete(res,1,1);:=res;;TForm1.DecompositeCommand(comstr:string):Command;posi:integer; oper,mark,arg1,arg2:string;

//обнуление параметров:

mark:='';:='';:='';

arg2:='';

//для форматов "mark:movax,bx; comments" =метка + команда с двумя операндами + комментарий

// "movax,bx" =команда с двумя операндами

// "incax" =команда с одним операндом

// "aam" =команда без операндов

//если строка является полностью комментарием

if length(comstr)>=1 then begin

posi:=1; while (comstr[posi]=' ')and(posi<length(comstr)) do inc(posi);comstr[posi]=';' then comstr:='';;

//установка ограничения для строки-команды

comstr:=comstr+' ';

//замена разделителя комментария (символ ';') на пробел

posi:=pos(';',comstr); if posi>0 then comstr[posi]:=' ';

//1)извлечение меткиposi:=1 to length(comstr) do if comstr[posi]=':' then begin:=copy(comstr,1,posi-1);(comstr,1,posi);;;

//2)извлечение мнемокода операцииposi:=1 to length(comstr) do if comstr[posi]=' ' then begin:=copy(comstr,1,posi-1);(comstr,1,posi);;;

//3)извлечение первого операндаposi:=1 to length(comstr) do if comstr[posi]=',' then begin:=copy(comstr,1,posi-1);(comstr,1,posi);;;

//4)извлечение второго операндаposi:=1 to length(comstr) do if (comstr[posi]=' ') then begin:=copy(comstr,1,posi-1);(comstr,1,posi);;

end;

//Для данного алгоритма: если второй операнд есть, а первого нет то это значит что команда одноаргументная:

//..нужно выполнить пересылку аргумента из 2 в 1:

if (arg1='')and(arg2<>'') then begin:=arg2;:='';;

//Запись результатов в параметр возвращаемый процедурой:

DecompositeCommand.mark:=mark;.oper:=oper;.arg1:=arg1;.arg2:=arg2;;

//Удаление пробелов перед и после команды, а также двойных пробелов и пробелов

//..перед символами разделения (запятая и т. д.)

function TForm1.DeleteSpace(str:string):string;ps:integer;str=' ' then str:='';str='' then exit;:=1;ps <= length(str) do begin(str[ps]=#9) then begin delete(str,ps,1); continue end;(ps);

end;

//удаление пробелов до и после команды:

while ((str[1]=' ')and(length(str)>1)) do delete(str,1,1);((str[length(str)]=' ')and(length(str)>1)) do delete(str,length(str),1);

//удаление повторных пробелов::=1; while ps <= length(str)-1 do begin(str[ps]=' ') then while (str[ps+1]=' ') do begin delete(str,ps,1); end;(ps);

end;

//удаление пробелов рядом с разделителем - запятой

ps:=Pos(',',str);

if ps>0 then beginstr[ps+1]=' ' then delete(str,ps+1,1);str[ps-1]=' ' then delete(str,ps-1,1);;:=str;;TForm1.ComIs:string; //Есть ли команда или уже конец файла(ComReadPos<Code.Lines.Count) then ComIs:=''ComIs:='EOF';;TForm1.ComNext:string; //Переход на следующую команду или сброс:

inc(ComReadPos);

end;

//Считывание очередной считанной команды и возврат её функцией в текстовом виде

function TForm1.ComRead:string;

//LowerCase - все буквы (от A до Z) устанавл. прописными:=LowerCase(DeleteSpace(Code.Lines[ComReadPos])); //DeleteSpace - удаление пробелов;

//Получение Imm16 с перестановкой байтов в Imm16 и убирание символа 'h'/'a'

function TForm1.ImmToHex(imm:string;len:string):string;HexChar:set of char=['0'..'9','A'..'F','a'..'f'];i,l,temp:integer;:char;imm='' then exit;:=-1;:= imm[Length(imm)];(imm,Length(imm),1);len ='dw' then l:=4;len ='db' then l:=2;:=1;i<=Length(imm) doimm[i] in HexChar then inc(i)Delete(imm,i,1);imm='' then exit;(imm[1]='0') and (length(imm)>1) do Delete(imm,1,1);:=0;c='b' then begin for i:=Length(imm) to 1 doimm[i]='1' then temp:=temp+ round(intpower(2,length(imm)-i));:=IntToHex(temp,l);end;length(imm)>l then begin ErrorControl:='<Несоответствие типов>';exit; end;length(imm)<l do imm:='0'+imm;:=Uppercase(imm);

end;

//Получение кода в 16 c/c, являющегося смещением относительно положения si (для операндов вида [si+N])

function TForm1.cnvData(dat:string):string;

ifpos('+',dat)>0 then //если указано смещение т.е. si+N, где N - велич. смещения

cnvData:=copy(dat,pos('+',dat)+1,2) //получение 2-х символов после символа +, подразумевается что эти символы число в 16 с/c

elsecnvData:='*'; //смещение не указано

end;

// Проверка на непосредственный операнд (пример movax,0140h - 0140h = Imm16):

function TForm1.isImm(arg:string):boolean;hexset: set of char=['0'..'9','a'..'f'];: set of char=['b','h'];pos:integer;Length(arg)<=1 then begin isImm:=false;exit;end;:=true;not (arg[length(arg)] in typeset) then begin isImm:=false;exit;end;pos:=1 to length(arg)-1 do if not (arg[pos] in hexset) then begin isImm:=false;exit;end;

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

for pos:=0 to length(Reg16)-1 do if (Reg16[pos]<>'') then if (arg=Reg16[pos]) then begin isImm:=false; break; end;pos:=0 to length(Reg8)-1 do if (Reg8[pos]<>'') then if (arg=Reg8[pos]) then begin isImm:=false; break; end;;

// Проверка на непосредственный операнд (пример movax,0140h - 0140h = Imm16):

function TForm1.isReg(arg:string):boolean;pos:integer;:=false; //убрать признак, что аргумент регистр:=''; //убрать информацию о длине регистра

//является ли операнд - регистром:pos:=0 to length(Reg16)-1 do if (Reg16[pos]<>'') then(arg=Reg16[pos]) then begin isReg:=true; RegLen:='R16'; exit; end;pos:=0 to length(Reg8)-1 do if (Reg8[pos]<>'') then(arg=Reg8[pos]) then begin isReg:=true; RegLen:='R8'; exit; end;;

// Проверка на взаимодействие с областью сегмента данных через si (movax,[si+4]):

function TForm1.isData(str:string):boolean;:=false;Pos('[',str)>0 then if Pos(']',str)>0 then if Pos('si',str)>0 then isData:=true;;

// Функция преобразования строки с шестнадцатеричными символами эквивалентной 1 байту в символ:

function TForm1.NexStrToStr(nexstr:string):string;length(nexstr)=2 then NexStrToStr:=chr(strtoint('$'+nexstr));length(nexstr)=4 then NexStrToStr:=chr(strtoint('$'+copy(nexstr,1,2)))+(strtoint('$'+copy(nexstr,3,2)));length(nexstr)=6 then NexStrToStr:=chr(strtoint('$'+copy(nexstr,1,2)))+(strtoint('$'+copy(nexstr,3,2)))+(strtoint('$'+copy(nexstr,5,2)));;TForm1.NewProgramButtonClick(Sender: TObject);

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

ComReadPos:=0;

//установка счетчика положения команд в байтах на начало

ComBytePos:=0;

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

DataBytes:=0;

//обнуление

marks.RowCount:=1; //таблицы поправок

varibles.RowCount:=1; //таблицы переменных

markslinks.RowCount:=1; //таблицы меток

//обнуление буферов - содержимых сегментов

VariableAdr:='';

ComBytePosMemo.Text:='';.Text:='';.Text:='';.Text:='';.Text:='';;TForm1.IsVar(arg:string):boolean; //Является ли аргумент переменнойi:integer;:=False;i:=1 to Form1.Varibles.RowCount doVaribles.Cells[0,i]=arg then begin:=True;:=Varibles.Cells[2,i];:=Varibles.Cells[3,i];;;;TForm1.GerArgType(Arg:string):string;:='';isReg(arg) then GerArgType:=RegLen;isVar(arg) then GerArgType:=VarLen;IsImm(arg) then GerArgType:='Imm';IsData(arg) then GerArgType:='Data';

//Возврат машинного кода после распознавания мнемокода, установка длины команды, проверка существования команды

function TForm1.AnalysisCommand (comstr:string):command;com:command;Type,Arg2Type:string;

com:=DecompositeCommand(comstr);

//обнуление выходных параметров - если программа не опознана то выводится

//..предупреждение о неизв. команде

com.MashCode:='';

com.ByteLen:='';

com.exist:=false; //первоначально команда считается не распознанной

with com do BEGINType:=GerArgType(arg1);Type:=GerArgType(arg2);:=Lowercase(oper);:=Lowercase(arg1);:=Lowercase(arg2);(oper='mov') then begin//------------------------------------------------MOV

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

//проверка правильности использования команды:

if (Arg1Type='R8') and (Arg2Type='R16') then begin ErrorControl:='<Неcоотв. типов арг.>'; exit; end;(Arg1Type='R16') and (Arg2Type='R8') then begin ErrorControl:='<Неcоотв. типов арг.>'; exit; end;(Arg1Type='V8') and (Arg2Type='R16') then begin ErrorControl:='<Неcоотв. типов арг.>'; exit; end;(Arg1Type='R16') and (Arg2Type='V8') then begin ErrorControl:='<Неcоотв. типов арг.>'; exit; end;(Arg1Type='V16') and (Arg2Type='R8') then begin ErrorControl:='<Неcоотв. типов арг.>'; exit; end;(Arg1Type='R8') and (Arg2Type='V16') then begin ErrorControl:='<Неcоотв. типов арг.>'; exit; end;

//проверка указания всех аргументов(arg1='')or(arg2='') then begin ErrorControl:='<Неуказ. все аргум.>'; exit; end;(arg1='ds') then if (arg2='ax') then begin //mov ax-ds:='8ED8';:='2'; end;

//reg to reg(Arg1Type='R16')and(Arg2Type='R16') then begin MashCode:='8B'+InsReg(InsRegMul('c0',arg1,8), arg2); ByteLen:='2'; end;//mov R16-R16(Arg1Type= 'R8')and(Arg2Type= 'R8') then begin MashCode:='8A'+InsReg(InsRegMul('c0',arg1,8), arg2); ByteLen:='2'; end; //mov R8-R8

//imm to reg(Arg1Type= 'R16')and(Arg2Type= 'Imm') then begin MashCode:=InsReg('B8',arg1)+InvertBytes(ImmToHex(arg2,'dw')); ByteLen:='3'; end; //mov R16-Imm16(Arg1Type= 'R8')and(Arg2Type= 'Imm') then begin MashCode:=InsReg('8A',arg1) +ImmToHex(arg2,'db'); ByteLen:='2'; end; //mov R8-Imm8

//var to reg(Arg1 = 'al')and(Arg2Type= 'V8') then begin MashCode:='A0'+InvertBytes(GetVarCodeByName(arg2));ByteLen:='3';VariableAdr:=VariableAdr+'C4'+IntToHex(combytepos+1,2)+'5401 ';end//mov al-var8if (Arg1Type= 'R8')and(Arg2Type= 'V8') then begin MashCode:='8A'+InsRegMul('06',arg1,8)+InvertBytes(GetVarCodeByName(arg2));VariableAdr:=VariableAdr+'C4'+IntToHex(combytepos+2,2)+'5401 ';ByteLen:='4';end;//mov R8-var8(Arg1 = 'ax')and(Arg2Type='V16') then begin MashCode:='A1'+InvertBytes(GetVarCodeByName(arg2));ByteLen:='3';VariableAdr:=VariableAdr+'C4'+IntToHex(combytepos+1,2)+'5401 ';end//mov ax-var16if (Arg1Type='R16')and(Arg2Type='V16') then begin MashCode:='8B'+InsRegMul('06',arg1,8)+InvertBytes(GetVarCodeByName(arg2));VariableAdr:=VariableAdr+'C4'+IntToHex(combytepos+2,2)+'5401 ';ByteLen:='4';end;//mov R16-var16

//reg to var(Arg2 = 'al')and(Arg1Type= 'V8') then begin MashCode:='A2'+InvertBytes(GetVarCodeByName(arg1));ByteLen:='3';VariableAdr:=VariableAdr+'C4'+IntToHex(combytepos+1,2)+'5401 ';end//mov var8-alif (Arg2Type= 'R8')and(Arg1Type= 'V8') then begin MashCode:='88'+InsRegMul('06',arg2,8)+InvertBytes(GetVarCodeByName(arg1));VariableAdr:=VariableAdr+'C4'+IntToHex(combytepos+2,2)+'5401 ';ByteLen:='4';end;//mov var8-R8(Arg2 = 'ax')and(Arg1Type='V16') then begin MashCode:='A3'+InvertBytes(GetVarCodeByName(arg1));ByteLen:='3';VariableAdr:=VariableAdr+'C4'+IntToHex(combytepos+1,2)+'5401 ';end//mov ax-var16if (Arg2Type='R16')and(Arg1Type='V16') then begin MashCode:='89'+InsRegMul('06',arg2,8)+InvertBytes(GetVarCodeByName(arg1));VariableAdr:=VariableAdr+'C4'+IntToHex(combytepos+2,2)+'5401 ';ByteLen:='4';end;//mov var16-R16(arg1='ax') then if (arg2='@data') or (arg2='data') then begin //mov ax-segname @Data

MashCode:='B8'+'0000';:='3';

//вспомогательный сегмент 9С05 для установки сегмента данных будет выведен:

ThisProgram.isDataSeg:=True; end;isReg(arg1) then if isData(arg2) then begin //mov Reg - data [si+n]cnvData(arg2)<>'*' then begin MashCode:='8B'+InsRegMul('44',arg1,8)+cnvData(arg2); ByteLen:='3'; endbegin MashCode:='8B'+InsRegMul('04',arg1,8); ByteLen:='2' end;;

//послепроверкаmashcode='' then ErrorControl:='<Неизв. аргумент>';;//---------------------------------------------------------------------/MOV

//Базовые команды:------------------------------------------------------------->

//int(oper='int') then if arg1type='Imm' then begin:='CD'+ImmToHex(arg1,'db');:='2';;

//nop(oper='nop') then begin MashCode:='90'; ByteLen:='1'; end;

// dec mark(oper='dec') then begin:='FF'+'0E'+InvertBytes(GetVarCodeByName(arg1));:='5';;

//jmp mark(oper='jg') then begin(arg1,'',inttostr(ComBytePos+2),inttostr(ComReadPos));:='7F';:='2';;

//add R16 - imm16(oper='add') then begin(arg1='ax') and (arg2Type='Imm') then begin MashCode:='05'+InvertBytes(ImmToHex(arg2,'dw')); ByteLen:='3'; end;

//ror R16 - imm8(oper='ror') then begin(Arg1Type='R16') and (Arg2Type='Imm') then begin

MashCode:='C1'+InsReg('C8',arg1)+ImmToHex(arg2,'db'); ByteLen:='3'; end;

end;

//mark: (место, куда осуществляется переход по метке)

if (mark<>'') then begin(mark,inttostr(ComBytePos));:=true;;;Com.MashCode<>'' then Com.exist:=true;:=com;;TForm1.Exit1Click(Sender: TObject);.Terminate; //выход из программы;TForm1.FormCreate(Sender: TObject);pos:integer;

//параметры программы

//изначально ни один из сегментов не присутствует

ThisProgram.isCodeSeg:=False;.isDataSeg:=False;

//имена регистров 16разр:

SetLength(Reg16,20); //число возможных регистров

for pos := 0 to Length(Reg16)-1 do Reg16[pos]:='';[0]:='ax';[1]:='cx';[2]:='dx';

Reg16[3]:='bx';[6]:='si';[7]:='di';

//имена регистров 8разр:

SetLength(Reg8,8); //число возможных регистров

for pos := 0 to Length(Reg8)-1 do Reg8[pos]:='';[0]:='al';[1]:='cl';[2]:='dl';[3]:='bl';[4]:='ah';[5]:='ch';8[6]:='dh';

Reg8[7]:='bh';

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

ComReadPos:=0;

//установка счетчика положения команд в байтах на начало

ComBytePos:=0;

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

DataBytes:=0;

//таблица меток

marks.RowCount:=1;

marks.Cells[0,0]:='Имя метки';

marks.Cells[1,0]:='Метка';

marks.Cells[2,0]:='Вызов метки';

marks.Cells[3,0]:='Строка';

//таблица переменных

varibles.RowCount:=1;

varibles.Cells[0,0]:='Имя';

varibles.Cells[1,0]:='Адрес';.Cells[2,0]:='Код';.Cells[3,0]:='Длина';

//таблица ссылок меток.RowCount:=1;.Cells[0,0]:='Имя';.Cells[1,0]:='Метка';:=''; //стирание сообщений об ошибках;TForm1.CharToByte(C:char):byte;cc:byte;:=0;c of

'0'..'9': cc:=strtoint(c);

'A':cc:=$A;

'B':cc:=$B;

'C':cc:=$C;

'D':cc:=$D;

'E':cc:=$E;

'F':cc:=$F;

end;:=cc;;TForm1.HexByteToByte(s:string):byte;:=((CharToByte(s[1]) shl 4)and(240))or((CharToByte(s[2])) and(15));TForm1.WriteHexStr(ss:string);:byte;:integer;:=1;i<=Length(ss) do begin:=HexByteToByte(copy(ss,i,2));(FileSave,bb);:=i+2;;;TForm1.StrDelSpaseHex(s:string):string;HexSet:set of Char=['0'..'9','A'..'F'];ss:string;:integer;:=1;:=s;i<=length(ss) donot (Uppercase(ss[i])[1] in HexSet) then Delete(ss,i,1)inc(i);:=ss;;Tform1.AddControlByte(s:string):string;sum,i:integer;:=1;sum:=0;:=StrDelSpaseHex(s);i<=length(s) do begin:=Sum+HexByteToByte(copy(s,i,2));:=i+2;;:=($100-sum mod $100)mod $100;:=Form1.IntToHexStr(sum);;TForm1.InvertBytes(s:string):string;//Сместить порядок байтовi:integer;:string;:='';i:=Length(s)div 2 downto 1 do:=ss+copy(s,2*i-1,2);:=ss;;TForm1.CreateObjFileClick(Sender: TObject);s,s1,s2:string;:integer;:array[1..6]of string;

//смещения прибавляемые к записям в объектном файле (+2 +4 +8)- зависят от длины след за них добавочных записей

//формирование заголовка

//1 строчка

s:=OpenDialog1.FileName;

for I:=length(S) downto 1 do if S[i]='\' then begin Delete(s,1,i);break;end;:=InvertBytes(IntToHex(length(S)+2,4));:=IntToHex(length(S),2);[1]:='80 '+s1+s2+StrToHexStr(S);[1]:=Strings[1]+AddControlByte(Strings[1]);[2]:='88 '+IntToHexStr(length('Turbo Assembler Version 4.1')+4)+'0000 001C'+StrToHexStr('Turbo Assembler Version 4.1');[2]:=Strings[2]+AddControlByte(Strings[2]);[3]:='88 '+IntToHexStr(length(S)+8)+'0040 E97A 74A5 4209 '+StrToHexStr(S);[3]:=Strings[3]+AddControlByte(Strings[3]);[4]:='98 07 00 60 '+IntToHexStr(DataBytes)+' 00 02 01 01 ';[4]:=Strings[4]+AddControlByte(Strings[4]);[5]:='98 07 00 60 '+IntToHexStr(ComBytePos)+' 00 03 01 01 ';[5]:=Strings[5]+AddControlByte(Strings[5]);.Text:=Strings[1]+#13#10+[2]+#13#10+[3]+#13#10+

'88 03 00 40 E9 4C'+#13#10+

'96 02 00 00 68'+#13#10+

'88 03 00 40 A1 94'+#13#10+

'96 06 00 04 44 41 54 41 46'+#13#10+[4]+#13#10+

'96 06 00 04 43 4F 44 45 45'+#13#10+[5]+#13#10+

'88 04 00 40 A2 01 91';

//формирование кодового сегмента.Text:='A0 '+InvertBytes(IntToHex(ComBytePos+4,4))+'02 0000'+StrDelSpaseHex(MashCode.Text);.Text:=CodeSeg.Text+AddControlByte(CodeSeg.Text);

//формировани сегмента данных

Strings[6]:='';

for i:=1 to Varibles.RowCount-1 do[6]:=Strings[6]+InvertBytes(Varibles.Cells[2,i]);.Text:='A0 '+InvertBytes(IntToHex(DataBytes+4,4))+' 01 00 00 '+Strings[6];.Text:=DataSeg.Text+AddControlByte(DataSeg.Text);.Text:='8A 0700 C100 0202 0000 AA';.Text:='9C '+InvertBytes(IntToHex(Length(StrDelSpaseHex(VariableAdr))div 2+1,4))+' '+VariableAdr;.Text:=DataSourceSeg.Text+AddControlByte(DataSourceSeg.Text);;TForm1.ClearCodeButtonClick(Sender: TObject); //очистка поля для ввода кода прогр..Clear;.Clear;.Clear;;TForm1.exeAllClick(Sender: TObject);(NewProgramButton);ComIs<>'EOF' do begin;;;; //пересылка всех меток из таблицы меток в таблицу поправок; //расчет смещений и добавление их к командам перехода

end;TForm1.CodeDblClick(Sender: TObject);:integer;:String;:=0;OpenDialog1.Execute then begin(FileLoad, OpenDialog1.FileName);(FileLoad);.Clear;.Clear;not eof(FileLoad) do(i);(FileLoad,Str);.Lines.Add(Str);.Lines.Add(IntToStr(I));;(FileLoad);;.Max:=Code.Lines.Count;.Position:= Code.Lines.Count;.Tag:=Code.Lines.Count;;TForm1.ScrollBar1Change(Sender: TObject);k:integer;:=ScrollBar1.Position-ScrollBar1.Tag;K>0 then begin.Perform (EM_SCROLL, SB_LINEDOWN, K);.Perform(EM_SCROLL, SB_LINEDOWN, K);.Perform (EM_SCROLL, SB_LINEDOWN, K);.Perform (EM_SCROLL, SB_LINEDOWN, K);begin.Perform (EM_SCROLL, SB_LINEUp, K);.Perform(EM_SCROLL, SB_LINEUp, K);.Perform (EM_SCROLL, SB_LINEUp, K);.Perform (EM_SCROLL, SB_LINEUp, K);;.Tag:=Scrollbar1.Position;;


Алгоритм работы программной реализации разрабатываемого компилятора


Компилятор, разработанный в данной курсовой работе, является однопроходным. Он использует две таблицы:

) Таблица переменных, состоящая из полей: имя, адрес, код и длина.

) Таблица меток(поправок), состоящая из полей: имя метки, положение метки, вызов метки, строка в которой вызывают метку.

Обработка происходит следующим образом.

Строка файла разбивается на 3 поля. Происходит обработка команд-директив или команд-операторов, также присутствуют проверки на строку-пустоту или строку - сплошной комментарий. Если директива то с помощью функции Data Table Write заносим в таблицу переменных название, адрес, машинный код и вычисляем длину. Если команда-оператор то определяем команду с помощью функции Analysis Command. Если команда с меткой, то переводим ее частично в машинный код и в таблицу меток записываем имя метки, адрес вызова метки и строку откуда вызывали. Если нашли метку записываем ее адрес в таблицу. После разбора всего файла вычисляем метки и добавляем к старым командам.


Заключение


Пример работы программы



Объектный код


Рис. 2 Получившийся объектный код при использовании компилятора TASM


Рис. 3 Получившийся объектный файл при работе программы


Расшифровка объектного кода откомпилированного примера.

80 0А 00 08 6B 6F 70 61 2E 61 73 6D 54 -запись названия исходного файла;

88 1A 00 00 00 1C 43 6F 6D 70 69 6C 65 72 20 4B 6F 70 79 6C 6F 76 61 20 4E 2E 53 2E 75 -- запись названия транслятора;

88 10 00 40 E9 34 67 C4 42 08 6B 6F 70 61 2E 61 73 6D 7C- вторая запись с название исходного файла;

88 03 00 40 E9 4C 96 02 00 00 68 88 03 00 40 A1 94- три постоянные записи;

96 06 00 04 44 41 54 41 46 -описания имени сегмента данных (DATА);

98 07 00 60 08 00 02 01 01 F5 - описание данных сегмента данных;

96 06 00 04 43 4F 44 45 45- описания имени сегмента кода (CODE);

98 07 00 60 15 00 03 01 01 E7- описание данных сегмента кода;

88 04 00 40 A2 01 91 - предсегментный блок;

A0 0C 00 01 00 00 01 10 00 01 01 01 00 4CF3- содержимое сегмента данных;

A0 19 00 02 00 00 A1 00 00 05 01 01 FF 0E 04 00 C1 C8 05 7F 01 90 A1 06 00 CD 21 59 - содержимое сегмента кода (A10000 - mov ax,a1, 050101FF - add ax,101h, 0E 04 00 - dec a3, C1 C8 05 - ror ax,5h, 7F 01 - jg @2, 90-nop, A1 06 00 - mov ax,c, CD 21 - int 21h);

9C 0D 00 C4 01 54 01 C4 08 54 01 C4 11 54 01 F2- таблица ссылок сегмента кода;

8A 0700 C100 0202 0000 AA - запись конца объектного файла.


Оглавление Введение Расчёт варианта задания Разработка контрольного примера Описание используемых директив и команд ассемблера Выбор варианта

Больше работ по теме:

КОНТАКТНЫЙ EMAIL: [email protected]

Скачать реферат © 2017 | Пользовательское соглашение

Скачать      Реферат

ПРОФЕССИОНАЛЬНАЯ ПОМОЩЬ СТУДЕНТАМ