Транслятор из языка С++ в язык Pascal
584770 584575
МИНИСТЕРСТВО ОБРАЗОВАНИЯ РФ
АЛТАЙСКИЙ
ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
КАФЕДРА
ВТиЭ
Курсовая работа по дисциплине
«Системное
ПО»
«Транслятор
из языка С++ в язык Pascal»
Барнаул 2007
Оглавление:
Постановка задачи
Задачей
данного курсового проекта
Процесс разработки разбит на 3 этапа:
- Проектирование и разработка лексического анализатора. Он выполняет поиск токенов в тексте исходной программы и формирует динамический список сформированный из токенов и их атрибутов.
- Проектирование и разработка синтаксического анализатора. Он анализирует список сформированный лексическим анализатором, и проводит проверку синтаксиса входного текста в соответствии с правилами грамматики.
- Проектирование и разработка транслятора. Он анализирует таблицу токенов, составленную после синтаксического анализатора, и формирует оттранслированную программу на языке Pascal.
Проектирование лексического анализатора
Лексический анализатор является первой фазой трансляции. Его основная задача состоит в чтении новых символов и построении таблицы токенов, которую в своей работе использует синтаксический анализатор.
В качестве промежуточного шага построим диаграммы переходов для поиска очередной лексемы.
Отделение ключевых слов от идентификаторов состоит в инициализации таблицы символов, в которой хранятся ключевые слова. Процедура gettoken просматривает таблицу символов в поисках ключевого слова. Если оно найдено, то возвращает соответствующий токен, в противном случае возвращает id, num или sym. Приведенная выше диаграмма может быть преобразована в программу поиска токенов.
Реализация лексического анализатора
// Лексический анализ.
void Lexan ()
{
InitSymbolTable();// Инициализация
таблицы ключевых слов.
int forward = 0;
int lineno = 1;
char lexeme[33];
TOKEN
token;
while ( GetLexemeLimit(forward, lineno,lexeme)) //Получаем новую лексему
{
token = GetTokenAndAttribute( lexeme ); //сравниваем текщую лексему с таблицей зарезервированных слов, определяем тип токена
AddTokenAndAttribu
forward++;
}
AddTokenAndAttribute( end_file, NULL, lineno );//Добавяем в конец таблицы токен конца файла
}
Для
начала работы лексического анализатора
нужно сначала определить зарезервированные
слова, для этого используется функция
InitSymbolTable. В качестве входного потока используется
файл, который в начале программы считывается
в буфер, непосредственно над которым
производится лексический анализ. Сложность
заключается в определении начала и конца
следующей лексемы, чем занимается функция
GetLexeme с её же помощью можно получить саму
лексему. Функция GetTokenAndAttribute просматривает
таблицу зарезервированных слов и возвращает
соответствующий лексеме токен, а функция
AddTokenAndAttribute записывает его в динамический
список. Сложность заключается в определении
границ лексем, поэтому его реализация
приведена ниже.
/* Ищет начало и конец лексемы,
и
записывает нужный кусок
bool GetLexeme(int &forward, int &lineno, char *lexeme)
{
aa:
int lexeme_begin = forward;
switch ( buf[forward] )
{
case '{': break;
case '}': break;
case '(': break;
case ')': break;
case ';': break;
case ',': break;
case ' ': forward++; goto aa;
case '\t': forward++; goto aa;
case '\n': forward++;
case
(char)13: forward++; goto aa;
case '!': if ( buf[++forward]=='=' ) break;
case '<': case '>': case '=': if ( buf[++forward]!='=' )
case '+': break;
case '-': break;
case '*': break;
case '/': forward++;
forward++; while(buf[forward]!='*'||buf[
if ( buf[forward]=='\0' )
error(11,lineno);
forward++;
while(buf[++forward]!='\
case '\'': if ( ! isalpha( buf[++forward] ))
error( 22, lineno );
error( 23, lineno );
if ( isalpha(buf[forward]) )
forward++;
forward++;
}
int i=0;
for (;lexeme_begin <= forward; i++, lexeme_begin++ ) //Записываем в переменную lexeme нужный кусок буфера с найденной лексемой)
lexeme[i] = buf[lexeme_begin];
lexeme[i]
= '\0';
}
Данная функция ищет лексемы в соответствии с диаграммой описанной при проектировании.
Проектирование синтаксического анализатора
Каждый язык программирования имеет грамматику, которая предписывает синтаксическую структуру корректных программ.
Грамматика:
start → main stmt_list eof
stmt_list → { stmts }
stmts → stmt ; stmts
stmt → if cmp stmt | stmts
| if cmp stmt | stmt_list else stmt | stmt_list
| do stmt | stmts while cmp
| while cmp stmt | stmt_list
| id = expr
| type id_list
| ε
Id_list → id, id_list
cmp → ( term relop term )
expr → term op expr_b
expr_b → op term expr_b | ε
term → ( expr ) | id | sym | num
type → char | int
id → letter ( letter | digit )*
sym →’letter’
num → digit ( digit )*
relop → < | <= | == | != | > | >=
Синтаксический анализатор получает последовательность токенов от лексического анализатора и проверяет может ли эта строка порождаться грамматикой исходного языка.
Т. к. в грамматике нет левой рекурсии ее можно проанализировать методом рекурсивного спуска. Для реализации метода рекурсивного спуска для каждого нетерминала имеется процедура проверяющая правильность построения последовательности токенов. Встреча очередного нетерминала во входном потоке означает вызов процедуры для этого нетерминала. Метод рекурсивного спуска неявным образом строит дерево разбора.
Реализация синтаксического анализатора
//-------------------------
void Syntax()
{
char TokenVal[33];
FirstToken();
Token = GetNextToken( TokenVal );
if ( Token != kw_main ) error( 2, lexeme_table->back->lineno
);
Token = GetNextToken( TokenVal );
if ( Token != lb ) error( 4, lexeme_table->back->lineno
);
Token = GetNextToken( TokenVal );
if ( Token != rb ) error( 6, lexeme_table->back->lineno
);
Token = GetNextToken( TokenVal );
if ( Token != lfb )
error( 3, lexeme_table->back->lineno );
stmt_list();
Token = GetNextToken( TokenVal );
if ( Token != end_file ) error( 18, lexeme_table->back->lineno );
}
//------------------------
void stmt_list()
{
stmt (false);
Token = GetNextToken( TokenVal );
while ( Token!=rfb ) {
stmt (true);
Token = GetNextToken( TokenVal );
}
}
//--------------------------
void stmt( bool read )
{
// Получить следующий токен если нужно.
if ( !read ) Token = GetNextToken( TokenVal
);
switch ( Token ) {
// if ( cmp ) (stmt | stmt_list) else (stmt | stmt_list).
case kw_if: cmp();
// id = expr;
case id:
// while (cmp) do ( stmt | stmt_list ).
case kw_while: cmp();
// do (stmt | stmt_list) while (cmp);
case kw_do: Token = GetNextToken( TokenVal );
case dc: break;
case rfb: lexeme_table = lexeme_table->back; break;//возвращаемся
к предыдущему токкену
case type: char id_type[5];
case end_file: error( 9, lexeme_table->back->lineno );
default: break;
}
}
//-----------------------
void var_list( char * id_type )
{
Token
= GetNextToken( TokenVal );
while ( Token != dc) {
if ( Token != id ) error( 13, lexeme_table->back->lineno );
if (! addIdTable ( id_type ) ) error( 14, lexeme_table->back->lineno );
Token = GetNextToken( TokenVal );
if ( Token != comma && Token != dc ) error( 15, lexeme_table->back->lineno );
if ( Token == comma ) Token = GetNextToken ( TokenVal );
}
}
//----------------------