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

Материал из Вики ИТ мехмата ЮФУ
Перейти к: навигация, поиск
(Модуль лексического анализатора)
(Модуль лексического анализатора)
Строка 1: Строка 1:
 
[[Страница_курса_%22Методы_построения_компиляторов%22| К основной странице курса]]
 
[[Страница_курса_%22Методы_построения_компиляторов%22| К основной странице курса]]
 +
 +
==== Предварительные замечания ====
 +
===== Лексемы языка: =====
 +
  ;  :=  +=  -=  *=  id  num  begin  end  cycle
 +
 +
Здесь
 +
  id - идентификатор
 +
  num - целое без знака
 +
  begin  end  cycle - ключевые слова
 +
 +
===== Глобальные переменные, необходимые для работы лексического анализатора: =====
 +
  fname: string;          // Имя файла программы
 +
  LexRow,LexCol: integer;  // Строка-столбец начала лексемы. Конец лексемы = LexCol+Length(LexText)
 +
  Lex: TLex;              // Тип лексемы 
 +
  LexText: string;        // Текст лексемы
 +
  LexValue: integer;      // Целое значение, связанное с лексемой lexNum
 +
 +
Тип TLex является перечислимым и содержит все возможные лексемы нашего языка, а также специальную лексему lexEot конца текста:
 +
  TLex = (lexId,lexNum,lexSemicolon,lexAssign,lexAssignPlus,lexAssignMinus,lexAssignMult,lexBegin,lexEnd,lexCycle,lexEot);
 +
  
 
==== Модуль лексического анализатора ====
 
==== Модуль лексического анализатора ====
Строка 22: Строка 42:
  
 
var  
 
var  
   fname: string;          // Имя файла програмы
+
   fname: string;          // Имя файла программы
 
   LexRow,LexCol: integer;  // Строка-столбец начала лексемы. Конец лексемы = LexCol+Length(LexText)
 
   LexRow,LexCol: integer;  // Строка-столбец начала лексемы. Конец лексемы = LexCol+Length(LexText)
 
   Lex: TLex;              // Тип лексемы   
 
   Lex: TLex;              // Тип лексемы   

Версия 15:52, 28 февраля 2012

К основной странице курса

Предварительные замечания

Лексемы языка:
 ;  :=  +=  -=  *=  id  num  begin  end  cycle

Здесь

 id - идентификатор
 num - целое без знака
 begin  end  cycle - ключевые слова
Глобальные переменные, необходимые для работы лексического анализатора:
 fname: string;           // Имя файла программы
 LexRow,LexCol: integer;  // Строка-столбец начала лексемы. Конец лексемы = LexCol+Length(LexText)
 Lex: TLex;               // Тип лексемы   
 LexText: string;         // Текст лексемы
 LexValue: integer;       // Целое значение, связанное с лексемой lexNum

Тип TLex является перечислимым и содержит все возможные лексемы нашего языка, а также специальную лексему lexEot конца текста:

 TLex = (lexId,lexNum,lexSemicolon,lexAssign,lexAssignPlus,lexAssignMinus,lexAssignMult,lexBegin,lexEnd,lexCycle,lexEot);


Модуль лексического анализатора

// Распознавание программы на простом языке. Распознаватель лексем (лексер)
{ 
  Лексемы:
  ;  :=  +=  -=  *=  id  num  begin  end  cycle
  
  Ключевые слова:
  begin  end  cycle
}
unit SimpleLangLexer1;

interface

// TLex - перечислимый тип - все лексемы грамматики
// lexEot - конец текста программы
type 
  TLex = (lexId,lexNum,lexSemicolon,lexAssign,lexAssignPlus,lexAssignMinus,lexAssignMult,lexBegin,lexEnd,lexCycle,lexEot);

var 
  fname: string;           // Имя файла программы
  LexRow,LexCol: integer;  // Строка-столбец начала лексемы. Конец лексемы = LexCol+Length(LexText)
  Lex: TLex;               // Тип лексемы   
  LexText: string;         // Текст лексемы
  LexValue: integer;       // Целое значение, связанное с лексемой lexNum

procedure NextCh;
procedure PassSpaces;
procedure NextLexem;
procedure Init(fn: string);
procedure Done;
procedure lexerror(message: string := '');

implementation

uses System.Collections.Generic;

var 
  ch: Char;         // Текущий символ
  f: text;          // Текущий файл
  row,col: integer; // Текущие строка и столбец в файле
  KeywordsMap := new Dictionary<string,TLex>; // Словарь, сопоставляющий ключевым словам константы типа TLex. Инициализируется процедурой InitKeywords

procedure lexerror(message: string);
begin
  var ss := System.IO.File.ReadLines(fname).Skip(row-1).First(); // Строка row файла
  writeln('Лексическая ошибка в строке ',row,':');
  writeln(ss);
  writeln('^':col-1);
  if message<>'' then 
    writeln(message);
  Done;  
  halt;
end;

procedure NextCh;
begin
  // В LexText накапливается предыдущий символ и считывается следующий символ
  LexText += ch;
  if not eof(f) then
  begin
    read(f,ch);
    if ch<>#10 then
      col += 1
    else
    begin
      row += 1;
      col := 1;
    end;
  end
  else ch := #0;  
end; 

procedure PassSpaces;
begin
  while char.IsWhiteSpace(ch) do
    NextCh;
end;

procedure NextLexem;
begin
  PassSpaces;
  LexText := '';
  LexRow := Row;
  LexCol := Col;
// Тип лексемы определяется по ее первому символу
// Для каждой лексемы строится синтаксическая диаграмма
  case ch of
  ';': begin
         NextCh;
         Lex := lexSemicolon;
       end;  
  ':': begin
         NextCh;
         if ch<>'=' then 
           lexerror('= ожидалось');
         NextCh;
         Lex := lexAssign;
       end;
  '+': begin
         NextCh;
         if ch<>'=' then 
           lexerror('= ожидалось');
         NextCh;
         Lex := lexAssignPlus;
       end;
  '-': begin
         NextCh;
         if ch<>'=' then 
           lexerror('= ожидалось');
         NextCh;
         Lex := lexAssignMinus;
       end;
  '*': begin
         NextCh;
         if ch<>'=' then 
           lexerror('= ожидалось');
         NextCh;
         Lex := lexAssignMult;
       end;
  'a'..'z': begin
         while ch in ['a'..'z','0'..'9'] do
           NextCh;
         if KeywordsMap.ContainsKey(LexText) then
           Lex := KeywordsMap[LexText]
         else Lex := lexId;
       end;
  '0'..'9': begin
         while ch in ['0'..'9'] do
           NextCh;
         LexValue := integer.Parse(LexText);
         Lex := lexNum;
       end;
    #0: Lex := lexEot;   
    else lexerror('Неверный символ '+ch);
  end;  
end;

procedure InitKeywords;
begin
  KeywordsMap['begin'] := lexBegin;
  KeywordsMap['end'] := lexEnd;
  KeywordsMap['cycle'] := lexCycle;
end;

procedure Init(fn: string);
begin
  InitKeywords;
  fname := fn;
  assign(f,fname);
  reset(f);
  row := 1; col := 1;
  NextCh;
  NextLexem;
end;

procedure Done;
begin
  close(f);
end;
 
end.