Создание лексического анализатора простого языка программирования — различия между версиями
Материал из Вики ИТ мехмата ЮФУ
Admin (обсуждение | вклад) (→Задания) |
Admin (обсуждение | вклад) (→Модуль лексического анализатора) |
||
Строка 52: | Строка 52: | ||
// lexEot - конец текста программы | // lexEot - конец текста программы | ||
type | type | ||
− | TLex = (lexId,lexNum,lexSemicolon,lexAssign | + | TLex = (lexId,lexNum,lexSemicolon,lexAssign,lexBegin,lexEnd,lexCycle,lexEot); |
var | var | ||
fname: string; // Имя файла программы | fname: string; // Имя файла программы | ||
LexRow,LexCol: integer; // Строка-столбец начала лексемы. Конец лексемы = LexCol+Length(LexText) | LexRow,LexCol: integer; // Строка-столбец начала лексемы. Конец лексемы = LexCol+Length(LexText) | ||
− | + | LexKind: TLex; // Тип лексемы | |
LexText: string; // Текст лексемы | LexText: string; // Текст лексемы | ||
LexValue: integer; // Целое значение, связанное с лексемой lexNum | LexValue: integer; // Целое значение, связанное с лексемой lexNum | ||
Строка 125: | Строка 125: | ||
';': begin | ';': begin | ||
NextCh; | NextCh; | ||
− | + | LexKind := lexSemicolon; | |
end; | end; | ||
':': begin | ':': begin | ||
Строка 132: | Строка 132: | ||
lexerror('= ожидалось'); | lexerror('= ожидалось'); | ||
NextCh; | NextCh; | ||
− | + | LexKind := lexAssign; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end; | end; | ||
'a'..'z': begin | 'a'..'z': begin | ||
Строка 159: | Строка 138: | ||
NextCh; | NextCh; | ||
if KeywordsMap.ContainsKey(LexText) then | if KeywordsMap.ContainsKey(LexText) then | ||
− | + | LexKind := KeywordsMap[LexText] | |
− | else | + | else LexKind := lexId; |
end; | end; | ||
'0'..'9': begin | '0'..'9': begin | ||
Строка 166: | Строка 145: | ||
NextCh; | NextCh; | ||
LexValue := integer.Parse(LexText); | LexValue := integer.Parse(LexText); | ||
− | + | LexKind := lexNum; | |
end; | end; | ||
− | #0: | + | #0: LexKind := lexEot; |
else lexerror('Неверный символ '+ch); | else lexerror('Неверный символ '+ch); | ||
end; | end; |
Версия 00:41, 14 марта 2013
Содержание
Предварительные замечания
Лексемы языка:
; := += -= *= 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);
Вспомогательные глобальные переменные, описанные в секции реализации модуля:
ch: Char; // Текущий символ f: text; // Текущий файл row,col: integer; // Текущие строка и столбец в файле KeywordsMap := new Dictionary<string,TLex>; // Словарь, сопоставляющий ключевым словам константы типа TLex. // Инициализируется процедурой InitKeywords
Процедура NextCh
Помимо считывания следующего символа ch, процедура NextCh поддерживает в актуальном состоянии текущие строку-столбец (row,col). При достижении конца файла в переменную ch возвращается специальный символ #0
Процедура InitKeywords
Процедура InitKeywords инициализирует словарь ключевых слов KeywordsMap. Этот словарь ставит в соответствие строке ключевого слова константу типа TLex:
KeywordsMap['begin'] := lexBegin;
Модуль лексического анализатора
// Распознавание программы на простом языке. Распознаватель лексем (лексер)
{
Лексемы:
; := += -= *= id num begin end cycle
Ключевые слова:
begin end cycle
}
unit SimpleLangLexer;
interface
// TLex - перечислимый тип - все лексемы грамматики
// lexEot - конец текста программы
type
TLex = (lexId,lexNum,lexSemicolon,lexAssign,lexBegin,lexEnd,lexCycle,lexEot);
var
fname: string; // Имя файла программы
LexRow,LexCol: integer; // Строка-столбец начала лексемы. Конец лексемы = LexCol+Length(LexText)
LexKind: 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;
LexKind := lexSemicolon;
end;
':': begin
NextCh;
if ch<>'=' then
lexerror('= ожидалось');
NextCh;
LexKind := lexAssign;
end;
'a'..'z': begin
while ch in ['a'..'z','0'..'9'] do
NextCh;
if KeywordsMap.ContainsKey(LexText) then
LexKind := KeywordsMap[LexText]
else LexKind := lexId;
end;
'0'..'9': begin
while ch in ['0'..'9'] do
NextCh;
LexValue := integer.Parse(LexText);
LexKind := lexNum;
end;
#0: LexKind := 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.
Задания
- Добавить распознавание лексем : , + - * / div mod and or not
- Добавить распознавание лексем += -= *= /=
- Добавить распознавание лексем > < >= <= = <>
- Добавить пропуск комментариев // - до конца строки
- Добавить пропуск комментариев { - до }
- Добавить распознавание вещественного с фиксированной точкой: 3.14. Их лексическое значение должно быть вещественным. Для этого
- Добавить распознавание строковых литералов: 'abc'