Транслятор из языка С++ в язык Pascal

584770 584575

МИНИСТЕРСТВО  ОБРАЗОВАНИЯ РФ

АЛТАЙСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ 

КАФЕДРА ВТиЭ 
 
 
 
 

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

«Системное  ПО»  
 

«Транслятор из языка С++ в язык Pascal» 
 
 
 

                                                      Выполнил:

                                                      студент группы  546

                                                                                           Шипулин Н. В.________ 

                                                      Проверил:

                                                      Зацепин П. М._________ 
 
 
 

Барнаул 2007

    Оглавление:

 

     Постановка  задачи

    Задачей данного курсового проекта является написание транслятора из языка  высокого уровня С++ в язык Pascal. Входными данными является текст программы на языке C++, а выходными текст оттранслированной программы на языке Pascal.

    Процесс разработки разбит на 3 этапа:

  1. Проектирование и разработка лексического анализатора. Он выполняет поиск токенов в тексте исходной программы и формирует динамический список сформированный из токенов и их атрибутов.
  2. Проектирование и разработка синтаксического анализатора. Он анализирует список сформированный лексическим анализатором, и проводит проверку синтаксиса входного текста в соответствии с правилами грамматики.
  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 );    //сравниваем текщую лексему с таблицей зарезервированных слов, определяем тип токена  

            AddTokenAndAttribute( token, lexeme, lineno );  //делаем запись в таблицу лексем  

            forward++;

      }  

      AddTokenAndAttribute( end_file, NULL, lineno );//Добавяем в конец таблицы токен конца файла

} 

    Для начала работы лексического анализатора  нужно сначала определить зарезервированные  слова, для этого используется функция  InitSymbolTable. В качестве входного потока используется файл, который в начале программы считывается в буфер, непосредственно над которым производится лексический анализ. Сложность заключается в определении начала и конца следующей лексемы, чем занимается функция GetLexeme с её же помощью можно получить саму лексему. Функция GetTokenAndAttribute просматривает таблицу зарезервированных слов и возвращает соответствующий лексеме токен, а функция AddTokenAndAttribute записывает его в динамический список. Сложность заключается в определении границ лексем, поэтому его реализация приведена ниже.   

/* Ищет начало и конец лексемы,

   и  записывает нужный кусок буфера, соответствующий найденной лексеме  в перменную lexeme */

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++;

                              lineno = lineno + 1;  goto aa;

                  case (char)13: forward++;    goto aa; 

                    case '!'if ( buf[++forward]=='=' ) break;                          

                              else error( 1, lineno);        

                  case '<': case '>'case '=':           if ( buf[++forward]!='=' )

                                          forward--;

                                    break; 

                  case '+'break;

                  case '-'break;

                  case '*'break;

                  case '/': forward++;

                              if ( buf[forward]=='*' ) // Комментарии типа "/*  */"

                              {

              forward++; while(buf[forward]!='*'||buf[forward+1]!='/')

                                          

                                                if ( buf[forward]=='\n' )            lineno++;

                     if ( buf[forward]=='\0' )

                       error(11,lineno);

                  forward++;

                                          

                                    forward++;

                              }

                              else if(buf[forward]=='/'// Комментарии типа  "//"

                                    {

                   while(buf[++forward]!='\n');

                                          lineno++;

                                          forward++;             

                                    }

                                    else {     // Оператор деления /

                                          forward--;

                                          break;

                                         }   

                                    forward++;  //Если дошло до этого места значит мы обнаружили комментарии

                                    goto aa;     //которые должны пропустить вернувшись к началу функции с новым forward

                  case '\''if ( ! isalpha( buf[++forward] ))

                    error( 22, lineno );   

                                                 if ( buf[++forward]!='\'' )

                       error( 23, lineno );

                                                 break;      

                                    default

                   if ( isalpha(buf[forward]) )

                                           {

                                              do

                                                {

                     forward++;

                                                }

                                             while(isalpha( buf[forward] )||

                                                               isdigit( buf[forward] ));

                                              forward--;

                                              break;

                                            }

                                           if ( isdigit(buf[forward]))

                                            {

                                               do

                                                {

                        forward++;

                                                }

                                               while(isdigit( buf[forward]));

                                               forward--;

                                               break;

                                             }

                                           if ( buf[forward]=='\0' ) return false;

                                           else error( 1, lineno );

            }

     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 ); 

} 
 

//------------------------Продукция stmt_list.---------------------------------

void stmt_list()

{

      stmt (false);

      Token = GetNextToken( TokenVal );

      while ( Token!=rfb ) {

            stmt (true);

            Token = GetNextToken( TokenVal );

      }

} 
 

//--------------------------Продукция stmt.--------------------------------------

void stmt( bool read )

{

      // Получить следующий токен если  нужно.

      if ( !read ) Token = GetNextToken( TokenVal ); 

      switch ( Token ) {

      // if ( cmp ) (stmt | stmt_list) else (stmt | stmt_list).

      case kw_if:  cmp(); 

                              Token = GetNextToken( TokenVal );

                              if ( Token == lfb ) stmt_list();

                                    else stmt( true );

                              Token = GetNextToken( TokenVal );

                              // Проверка присутствия else.

                              if ( Token == kw_else ) {

                                    Token = GetNextToken( TokenVal );

                                    if ( Token == lfb ) stmt_list();

                                    else stmt( true );

                              }

                              else lexeme_table = lexeme_table->back;//возвращаемся к предыдущему токкену

                              break;

      // id = expr;

      case id:  

                              Token = GetNextToken( TokenVal );

                              if ( Token != app ) error( 7, lexeme_table->back->lineno );

                              expr();

                              if ( Token != dc ) error( 12, lexeme_table->back->lineno );

                              break;

      // while (cmp) do ( stmt | stmt_list ).

      case kw_while: cmp();

                              Token = GetNextToken( TokenVal );

                              if ( Token == lfb ) stmt_list();

                              else stmt( true );

                              break;

      // do (stmt | stmt_list) while (cmp);

      case kw_do:  Token = GetNextToken( TokenVal );

                              if ( Token == lfb ) stmt_list();

                              else stmt( true );

                              Token = GetNextToken( TokenVal );

                              if ( Token != kw_while ) error( 10, lexeme_table->back->lineno );

                              strcpy( lexeme_table->back->attribute, "DO" );

                              cmp();

                              Token = GetNextToken( TokenVal );

                              if ( Token != dc ) error( 11, lexeme_table->back->lineno );

                              break;

      case dc:  break;

      case rfb:  lexeme_table = lexeme_table->back; break;//возвращаемся к предыдущему токкену 

      case type:  char id_type[5];

                              strcpy( id_type, TokenVal );  

                              var_list( id_type );

                              break; 

      case end_file: error( 9, lexeme_table->back->lineno );

      default:  break;   

      }

} 

//-----------------------Продукция var_list.-----------------------------------

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 );

      }

} 

//----------------------Проверка  условия---------------------------------------------