Документация для пользователя

Федеральное Агентство образования РФ

Государственное образовательное учреждение

высшего профессионального образования

Владимирский государственный университет

Кафедра вычислительной техники

 

 

Пояснительная записка

к курсовой работе

по дисциплине

«системное программное обеспечение»

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

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; Мы поможем в написании вашей работы!

Поделиться с друзьями:




Мы поможем в написании ваших работ!