Документация для пользователя
Федеральное Агентство образования РФ
Государственное образовательное учреждение
высшего профессионального образования
Владимирский государственный университет
Кафедра вычислительной техники
Пояснительная записка
к курсовой работе
по дисциплине
«системное программное обеспечение»
Разработка компилятора
c языка Pascal на язык Assembler
выполнил:
студент гр. ИВТ-302
Бережной А.М.
Проверил:
Лобачёв Г.А.
Владимир 2004
Содержание:
1. Введение
2. Цели и требования
3. Внешний проект
4. Проект архитектуры
5. Реализация
6. Заключение
Список литературы
Приложения
Введение
В данной курсовой работе необходимо разработать компилятор языка высокого уровня.
Всякий компилятор является составной частью системного программного обеспечения. Основное назначение компиляторов — служить для разработки новых прикладных программ с помощью языков высокого уровня.
Любая программа, как системная, так и прикладная проходит этапы жизненного цикла, начиная от проектирования и вплоть до внедрения и сопровождения. А компиляторы — это средства, служащие для создания программного обеспечения на этапах кодирования, тестирования и отладки.
Однако, сам по себе компилятор не решает полностью всех задач, связанных с разработкой новой программы. Средств только лишь компилятора недостаточно для того, чтобы обеспечить прохождение программой указанных этапов жизненного цикла. Поэтому компиляторы — это программное обеспечение, которое функционирует в тесном взаимодействии с другими техническими средствами.
|
|
Работая с любой системой программирования, следует помнить, что основным ее модулем всегда является компилятор. Именно технические характеристики компилятора, прежде всего, влияют на эффективность результирующих программ, порождаемых системой программирования.
Цели и требования
Целью выполнения данной курсовой работы – формирование представления о процессе компиляции, его стадиях и возможных вариантах реализации.
Исходные данные:
Входной язык — PASCAL
Выходной язык — Assembler
Язык реализации — Visual C++ 6.0
Внешний проект
Компиляция происходит с использованием следующей грамматики:
Программа:
тело:
раздел описаний:
Описание метки
Описание переменной
метка:
идентификатор:
Составной оператор:
оператор:
оператор присваивания:
Оператор if
Оператор goto
Выражение
Оператор writeln:
Структура генерируемого ассемблерного файла следующая:
|
|
.model small
.stack 128
.data
описание переменных
.code
код программы
Список ошибок компиляции:
VAR_NOT_FOUND - не найдено ключевое слово var в начале программы
TOO_LONG_STRING - слишком длинная строка
UNRESOLVED_ID_NAME – неразрешённое имя идентификатора
UNRESOLVED_TYPE – неразрешённый тип
TOO_LONG_IDENTIFIER_NAME – слишком длинное имя идентификатора
NOT_EXPECTED – ожидался символ ‘;’
NOT_EXPECTED2 - ожидался символ ‘:’
NOT_EXPECTED3 - ожидался символ ‘)’
UNKNOWN_SENTENSE – неизвестный оператор
INVALID_COMPARE – неверная функция сравнения
THEN_EXPECTED – ожидалось ключевое слово then
UNDECLARED_ID – необъявленный идентификатор
основные модули:
compiler.cpp — модуль с основной программой; содержит все функции необходимые для компиляции
compiler.h – содержит объявления функций и констант
error.h — функция обработки ошибок.
IdTableElement.h — класс элемента таблицы идентификаторов.
list.h — обобщённый класс связного списка.
Проект архитектуры
Алгоритм работы:
Работу данного компилятора можно разбить на три основные части:
1. Генерация таблицы идентификаторов
На данном этапе из входного файла считывается строка либо же её некоторая часть и определяется переменная какого типа и с каким именем описана в данной строке, после этого она помещается в таблицу идентификаторов.
|
|
2. Генерация кода и его запись в некоторый временный файл
На данном этапе из входного файла считывается строка либо же её некоторая часть и определяется класс лексемы (метка, выражение, условие, переход) и в зависимости от этого вызывается соответствующая функция генерации кода
3. Cоздание окончательного asm файла
В связи с тем, что при вычислении выражений промежуточные вычисления хранятся в переменных, которые добавляет сам компилятор, для генерации конечного файла требуется полная информация по всем используемым переменным.
Работа на данном этапе сводится к тому чтобы добавить в ассемблерный файл объявления дополнительных переменных, дописать процедуру вывода на экран, скопировать код, полученный на втором этапе и записать в конечный файл.
Спецификации функций:
void geuUnicName(char firstFor[5],int n,char uni[ID_NAME_SIZE]);
генерарция уникального имени
SentenseType analyseSentense()
Возвращает какое ключевое слово находится в прочитанной строке
void gotoToAsm()
генерация ассемблерского кода для оператора goto
void labelToAsm()
генерация аасемблерского кода для метки
|
|
void ifToAsm()
генерация ассемблерного кода для if
Дерево вызовов
Main
|_genIdTable
| |_readUpTo
| | |_error
| |
| |_addToIdTable
| | |_IdTable.add
| |
| |_ stringComp
| |_error
| |_correctIdentifier
| |_stringComp
|
|_reinterpret
| |_readUpTo
| | |_error
| |
| |_gotoToAsm
| | |_IdTable.find
| | |_error
| |
| |_labelToAsm
| | |_IdTable.find
| | |_error
| |
| |_analyseSentense
| | |_stringComp
| |
| |_ifToAsm
| | |_stringComp
| | |_error
| | |_readUpTo
| | |_genUnicName
| | |_reinterpret
| |
| |_createPolishString
| | |_Stack.push
| | |_Stack.pop
| | |_Stack.getFirst
| | |_error
| |
| |_exprToAsm
| | |_genUnicName
| | |_modifyExpr
| |
| |_writeToAsm
| | |_IdTable.find
| | |_error
| |
| |_stringComp
| |_reinterpret
| |_error
|
|_genEndFile
|_stringComp
|_genUnicName
Реализация
Тестирование процедуры gotoToAsm
1) если ch !=’;’ то выдаётся ошибка NOT_EXPECTED
2)если ch = =’;’ но name не найден в т.и. то выдаётся ошибка UNDECLARED_ID
3) если ch = =’;’ и name найден в т.и то name записывается в вых.файл
1)если name не обнаружено в т.и то Error(UNDECLARED_ID,lineNumber)
2) если name не обнаружено в т.и то запись name в вых файл и переход на новую строку
Внешнее тестирование
Пример №1: Вычислить 2 в степени 5
Текст программы:
var
result:integer;
a:integer;
power:integer;
label l1;
begin
power:=5;
a:=2;
result:=1;
l1:
result:= result*a;
power:=power-1;
if power > 0 then goto l1;
writeln(result);
end.
Текст программы на ассемблере:
.model small
.stack 128
.data
power dw ?
a dw ?
result dw ?
tmp_1 dw ?
st_1 db 4 dup(?),'$'
.code
write proc near
mov cl,16-4
mov di,0
Repeat:
mov ax,bx
shr ax,cl
and al,0Fh
add al,'0'
cmp al,'9'
jbe Digit09
add al,'A'-('9'+1)
Digit09:
mov st_1[di],al
inc di
sub cl,4
cmp cl,0
jge Repeat
lea dx, st_1
mov ah,9
int 21h
mov ah, 2
mov dl, 0Ah
int 21h
ret
write endp
main proc far
mov ax, @data
mov ds, ax
mov ax, 5
mov power, ax
mov ax, 2
mov a, ax
mov ax, 1
mov result, ax
l1:
mov ax, result
mov bx, a
mul bx
mov tmp_1, ax
mov ax, tmp_1
mov result, ax
mov ax, power
mov bx, 1
sub ax, bx
mov tmp_1, ax
mov ax, tmp_1
mov power, ax
mov ax, power
mov bx, 0
cmp ax, bx
jle els_1
jmp l1
els_1:
mov bx, result
call write
mov ah,1 ;waiting
int 21h
mov ax, 4C00h
int 21h
main endp
end main
На экран выводится число 0020 (в шестнадцатеричной СС)
Пример №2: Вычислить максимальное из трёх чисел (5, 20, 9)
Текст программы:
var
a1:integer;
a2:integer;
a3:integer;
max:integer;
begin
a1:=5;
a2:=20;
a3:=9;
if a1 > a2 then max:=a1;
else max:=a2;
if max < a3 then max:=a3;
writeln(max);
end.
Текст программы на ассемблере:
.model small
.stack 128
.data
max dw ?
a3 dw ?
a2 dw ?
a1 dw ?
st_1 db 4 dup(?),'$'
.code
write proc near
mov cl,16-4
mov di,0
Repeat:
mov ax,bx
shr ax,cl
and al,0Fh
add al,'0'
cmp al,'9'
jbe Digit09
add al,'A'-('9'+1)
Digit09:
mov st_1[di],al
inc di
sub cl,4
cmp cl,0
jge Repeat
lea dx, st_1
mov ah,9
int 21h
mov ah, 2
mov dl, 0Ah
int 21h
ret
write endp
main proc far
mov ax, @data
mov ds, ax
mov ax, 5
mov a1, ax
mov ax, 20
mov a2, ax
mov ax, 9
mov a3, ax
mov ax, a1
mov bx, a2
cmp ax, bx
jle els_1
mov ax, a1
mov max, ax
jmp nel_1
els_1:
mov ax, a2
mov max, ax
nel_1:
mov ax, max
mov bx, a3
cmp ax, bx
jge els_2
mov ax, a3
mov max, ax
els_2:
mov bx, max
call write
mov ah,1 ;waiting
int 21h
mov ax, 4C00h
int 21h
main endp
end main
На экран выводится число 0014 (в шестнадцатеричной СС)
Приложение
1.глобальные переменные:
enum SentenseType{EXPRESSION, IF_STATEMENT, GOTO,
WRITE, BEGIN, LABEL_STATE, UNKNOWN};
List<IdTableElement> IdTable;
FILE *sourceFile=NULL;
FILE *asmFile=NULL;
char buf[READING_STRING_SIZE]; //current string
int lineNumber=1; //current line
int recourse=-1;
int ifCounter=0;
int operationCounter=0;
char ch; //last char
2.процедура genUnicName:
void genUnicName(char firstFor[5], int n, char uni[ID_NAME_SIZE])
{
char strN[10];
itoa(n, strN, 10);
uni[0]=firstFor[0];
uni[1]=firstFor[1];
uni[2]=firstFor[2];
uni[3]=firstFor[3];
for(int i=0; i<2; ++i)
{
uni[i+4]=strN[i];
}
uni[6]='\0';
}
3.процедура analyseSentense
SentenseType analyseSentense()
{
SentenseType st=UNKNOWN;
//expression?
int i=0;
while (buf[i]!='\0')
{
if(buf[i]==':' && buf[i+1]=='=' )
{
st=EXPRESSION;
return st;
}
if (i>ID_NAME_SIZE)
break;
i++;
};
//writeln?
i=0;
char tmp[9];
for(i=0; i<8; i++)
{
tmp[i]=buf[i];
}
tmp[i]='\0';
if(stringComp(tmp,"writeln("))
{
st=WRITE;
return st;
}
//if?
if(stringComp(buf,"if"))
{
st=IF_STATEMENT;
return st;
}
//goto?
if(stringComp(buf,"goto"))
{
st=GOTO;
return st;
}
//begin?
if(stringComp(buf,"begin"))
{
st=BEGIN;
return st;
}
//label?
i=0;
char c=' ';
while (buf[i]!='\0')
{
c=buf[i];
i++;
}
if(c==':')
{
st=LABEL_STATE;
return st;
}
return st;
}
Процедура gotoToAsm
void gotoToAsm()
{
readUpTo(';');
if(ch!=';')
error(NOT_EXPECTED,lineNumber);
fputs("\tjmp\t",asmFile);
//check is label declared
char name[ID_NAME_SIZE];
int i=0;
while(buf[i]!='\0')
{
name[i]=buf[i];
i++;
};
name[i]='\0';
IdTableElement ie(name,LABEL);
if(!IdTable.find(ie))
error(UNDECLARED_ID, lineNumber);
fputs(name, asmFile);
fputc('\n', asmFile);
}
5.процедура labelToAsm
void labelToAsm()
{
char name[ID_NAME_SIZE];
int i=0;
while(buf[i]!=':')
{
name[i]=buf[i];
i++;
};
name[i]='\0';
IdTableElement ie(name,LABEL);
if(!IdTable.find(ie))
error(UNDECLARED_ID, lineNumber);
i=0;
while (buf[i]!='\0')
{
fwrite(&buf[i], sizeof(char),1,asmFile);
i++;
};
fputc('\n', asmFile);
}
Процедура ifToAsm
void ifToAsm()
{
char op1[ID_NAME_SIZE];
char op2[ID_NAME_SIZE];
char unicElseLabel[ID_NAME_SIZE];
char unicNotElseLabel[ID_NAME_SIZE];
bool valid=false,
jg=false,
jl=false,
jne=false,
je=false,
jle=false,
jge=false;
int i=0;
ifCounter++;
readUpTo(' ');
while(buf[i]!='\0')
{
op1[i]=buf[i];
++i;
}
op1[i]='\0';
readUpTo(' ');
if(stringComp(buf,"<="))
{
valid=true;
jg=true;
}
if(stringComp(buf,">="))
{
valid=true;
jl=true;
}
if(stringComp(buf,"="))
{
valid=true;
jne=true;
}
if(stringComp(buf,"<>"))
{
valid=true;
je=true;
}
if(stringComp(buf,">"))
{
valid=true;
jle=true;
}
if(stringComp(buf,"<"))
{
valid=true;
jge=true;
}
if(!valid)
error(INVALID_COMPARE,lineNumber);
readUpTo(' ');
i=0;
while(buf[i]!='\0')
{
op2[i]=buf[i];
++i;
}
op2[i]='\0';
readUpTo(' ');
if(!stringComp(buf,"then"))
error(THEN_EXPECTED,lineNumber);
fputs("\tmov\tax, ",asmFile);
i=0;
while (op1[i]!='\0')
{
fwrite(&op1[i], sizeof(char),1,asmFile);
i++;
}
fputc('\n', asmFile);
fputs("\tmov\tbx, ",asmFile);
i=0;
while (op2[i]!='\0')
{
fwrite(&op2[i], sizeof(char),1,asmFile);
i++;
}
fputc('\n', asmFile);
fputs("\tcmp\tax, bx",asmFile);
fputc('\n', asmFile);
genUnicName("els_",ifCounter,unicElseLabel);
if(jg)
{
fputs("\tjg\t", asmFile);
fputs(unicElseLabel, asmFile);
}
if(jl)
{
fputs("\tjl\t", asmFile);
fputs(unicElseLabel, asmFile);
}
if(jne)
{
fputs("\tjne\t", asmFile);
fputs(unicElseLabel, asmFile);
}
if(je)
{
fputs("\tje\t", asmFile);
fputs(unicElseLabel, asmFile);
}
if(jle)
{
fputs("\tjle\t", asmFile);
fputs(unicElseLabel, asmFile);
}
if(jge)
{
fputs("\tjge\t", asmFile);
fputs(unicElseLabel, asmFile);
}
fputc('\n', asmFile);
reinterpret(recourse, 1); // 1 - reinterpret one operator
fpos_t filepos;
fgetpos(sourceFile, &filepos); //save file pointer
int tmp=lineNumber;//save line number
bool elseFlag=false;
readUpTo(' ');
if (stringComp(buf, "else"))
{
cout<<"\nELSE\n";
genUnicName("nel_",ifCounter,unicNotElseLabel);
fputs("\tjmp\t", asmFile);
fputs(unicNotElseLabel,asmFile);
fputc('\n',asmFile);
elseFlag=true;
}
else
{
fsetpos(sourceFile, &filepos); //restore file pointer and lineNumber
lineNumber=tmp;
}
fputs(unicElseLabel,asmFile);
fputs(":\n",asmFile);
if (elseFlag)
{
reinterpret(recourse, 1);
fputs(unicNotElseLabel,asmFile);
fputs(":\n",asmFile);
}
}
Документация для пользователя
Правила пользования:
1. создать файл "prog.pas" и поместить в каталог, где находиться Compiler.exe
2. Запустить Compiler.exe при успешной компиляции будет cоздан файл "program.asm"
3. Поместить файл 'program.asm' в каталог ASM и запустить Build.bat
при отсутствии ошибок будет создан файл Program.exe
4. Запустить program.exe
Все выводимые данные записаны в 16-ричной СС.
Требования к входной программе:
1. Програма должна начинаться с ключевого слова var
2. В ключевых словах не должны использоваться заглавные буквы
3. В операторе IF при указании операции сравнения пробелы между операндами и этой операцией сравнения обязательны
4. В именах переменных могут использоваться строчные буквы a...z и цифры 0...9 но первый символ обязательно буква
5. В объявлении типа a:integer вокруг символа ':' не должно быть пробелов
6. В выражениях должны содержаться только объявленные переменные и литералы (отсутсвует различие в интерпретации литералов и переменных)
Дата добавления: 2018-05-12; просмотров: 259; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!