Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
13
Добавлен:
02.05.2014
Размер:
17.84 Кб
Скачать
unit LexAuto; {!!! Зависит от входного языка !!!}

interface
{ Модуль, обеспечивающий построение таблицы лексем
по исходному тексту программы }

uses Classes, TblElem, LexType, LexElem;

{ Функция создания списка лексем по исходному
тексту программы }
function MakeLexList(listFile: TStrings;
listLex: TLexList): integer;

implementation

uses SysUtils, FncTree;

type
{ Перечень всех возможных состояний конечного автомата }
TAutoPos = (
AP_START,AP_IF1,AP_IF2,AP_NOT1,AP_NOT2,AP_NOT3,
AP_ELSE1,AP_ELSE2,AP_ELSE3,AP_ELSE4,AP_END2,AP_END3,
AP_PROG1,AP_PROG2,AP_PROG3,AP_PROG4,AP_OR1,AP_OR2,
AP_BEGIN1,AP_BEGIN2,AP_BEGIN3,AP_BEGIN4,AP_BEGIN5,
AP_XOR1,AP_XOR2,AP_XOR3,AP_AND1,AP_AND2,AP_AND3,
AP_WHILE1,AP_WHILE2,AP_WHILE3,AP_WHILE4,AP_WHILE5,
AP_COMM,AP_COMMSG,AP_ASSIGN,AP_VAR,AP_CONST,
AP_DO1,AP_DO2,AP_SIGN,AP_LT,AP_FIN,AP_ERR);

function MakeLexList(listFile: TStrings;
listLex: TLexList): integer;
{ Функция создания списка лексем по исходному
тексту программы }
var
i,j,iCnt,iStr, { Переменные и счетчики циклов }
iAll,{ Счетчик общего количества входных символов }
{ Переменные для запоминания позиции начала лексемы }
iStComm,iStart: integer;
posCur: TAutoPos;{ Текущее состояние конечного автомата }
{ Строки для временного хранения результатов }
sCurStr,sTmp: string;
{ Несколько простых процедур для работы со списком лексем }
procedure AddVarToList(posNext: TAutoPos; iP: integer);
{ Процедура добавления переменной в список }
begin
{ Выделяем имя переменной из текущей строки }
sTmp := System.Copy(sCurStr,iStart,iP-iStart);
{ При создании переменной она сначала заносится
в таблицу идентификаторов, а потом ссылка на нее -
в таблицу лексем }
listLex.Add(TLexem.CreateVar(AddTreeVar(sTmp),
iStComm,i,iStart));
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure AddVarKeyToList(keyAdd: TLexType;
posNext: TAutoPos);
{ Процедура добавления переменной и
разделителя в список }
begin
{ Выделяем имя переменной из текущей строки }
sTmp := System.Copy(sCurStr,iStart,j-iStart);
{ При создании переменной она сначала заносится
в таблицу идентификаторов, а потом ссылка на нее -
в таблицу лексем }
listLex.Add(TLexem.CreateVar(AddTreeVar(sTmp),
iStComm,i,iStart));
{ Добавляем разделитель после переменной }
listLex.Add(TLexem.CreateKey(keyAdd,iAll,i,j));
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure AddConstToList(posNext: TAutoPos; iP: integer);
{ Процедура добавления константы в список }
begin
{ Выделяем константу из текущей строки }
sTmp := System.Copy(sCurStr,iStart,iP-iStart);
{ Заносим константу в список вместе с ее значением }
listLex.Add(TLexem.CreateConst(StrToInt(sTmp),
iStComm,i,iStart));
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure AddConstKeyToList(keyAdd: TLexType;
posNext: TAutoPos);
{ Процедура добавления константы и разделителя в список }
begin
{ Выделяем константу из текущей строки }
sTmp := System.Copy(sCurStr,iStart,j-iStart);
{ Заносим константу в список вместе с ее значением }
listLex.Add(TLexem.CreateConst(StrToInt(sTmp),iStComm,
i,iStart));
{ Добавляем разделитель после константы }
listLex.Add(TLexem.CreateKey(keyAdd,iAll,i,j));
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure AddKeyToList(keyAdd: TLexType;
posNext: TAutoPos);
{ Процедура добавления ключевого слова или
разделителя в список }
begin
listLex.Add(TLexem.CreateKey(keyAdd,iStComm,i,iStart));
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure Add2KeysToList(keyAdd1,keyAdd2: TLexType;
posNext: TAutoPos);
{ Процедура добавления ключевого слова и
разделителя в список }
begin
listLex.Add(TLexem.CreateKey(keyAdd1,iStComm,i,iStart));
listLex.Add(TLexem.CreateKey(keyAdd2,iAll,i,j));
iStart := j;
iStComm := iAll-1;
posCur := posNext;
end;
procedure KeyLetter(chNext: char; posNext: TAutoPos);
{ Процедура проверки очередного символа ключевого слова }
begin
case sCurStr[j] of
':': AddVarToList(AP_ASSIGN,j);
'-': AddVarKeyToList(LEX_SUB,AP_SIGN);
'+': AddVarKeyToList(LEX_ADD,AP_SIGN);
'=': AddVarKeyToList(LEX_EQ,AP_SIGN);
'>': AddKeyToList(LEX_GT,AP_SIGN);
'<': AddVarToList(AP_LT,j);
'(': AddVarKeyToList(LEX_OPEN,AP_SIGN);
')': AddVarKeyToList(LEX_CLOSE,AP_START);
';': AddVarKeyToList(LEX_SEMI,AP_START);
'{': AddVarToList(AP_COMM,j);
' ',#10,#13,#9: AddVarToList(AP_START,j);
else
if sCurStr[j] = chNext then posCur := posNext
else
if sCurStr[j] in ['0'..'9','A'..'Z','a'..'z','_']
then posCur := AP_VAR
else posCur := AP_ERR;
end{case list};
end;
procedure KeyFinish(keyAdd: TLexType);
{ Процедура проверки завершения ключевого слова }
begin
case sCurStr[j] of
'-': Add2KeysToList(keyAdd,LEX_UMIN,AP_SIGN);
'+': Add2KeysToList(keyAdd,LEX_ADD,AP_SIGN);
'=': Add2KeysToList(keyAdd,LEX_EQ,AP_SIGN);
'>': Add2KeysToList(keyAdd,LEX_GT,AP_SIGN);
'<': AddKeyToList(keyAdd,AP_LT);
'(': Add2KeysToList(keyAdd,LEX_OPEN,AP_SIGN);
')': Add2KeysToList(keyAdd,LEX_CLOSE,AP_START);
';': Add2KeysToList(keyAdd,LEX_SEMI,AP_START);
'0'..'9','A'..'Z','a'..'z','_': posCur := AP_VAR;
'{': AddKeyToList(keyAdd,AP_COMMSG);
' ',#10,#13,#9: AddKeyToList(keyAdd,AP_SIGN);
else posCur := AP_ERR;
end{case list};
end;
begin
{ Обнуляем общий счетчик символов и результат функции }
iAll := 0;
Result := 0;
iStComm := 0;
{ Устанавливаем начальное состояние конечного автомата }
posCur := AP_START;
{ Цикл по всем строкам входного файла }
iCnt := listFile.Count-1;
for i:=0 to iCnt do
begin
{ Позиция начала лексемы - первый символ }
iStart := 1;
{ Запоминаем текущую строку }
sCurStr := listFile[i];
{ Цикл по всем символам текущей строки }
iStr := Length(sCurStr);
for j:=1 to iStr do
begin
{ Увеличиваем общий счетчик символов }
Inc(iAll);
{ Моделируем работу конечного автомата в зависимости
от состояния КА и текущего символа входной строки }
case posCur of
AP_START:
begin
{ В начальном состоянии запоминаем позицию
начала лексемы }
iStart := j;
iStComm := iAll-1;
case sCurStr[j] of
'b': posCur := AP_BEGIN1;
'i': posCur := AP_IF1;
'p': posCur := AP_PROG1;
'e': posCur := AP_ELSE1;
'w': posCur := AP_WHILE1;
'd': posCur := AP_DO1;
'o': posCur := AP_OR1;
'x': posCur := AP_XOR1;
'a': posCur := AP_AND1;
'n': posCur := AP_NOT1;
':': posCur := AP_ASSIGN;
'-': AddKeyToList(LEX_SUB,AP_SIGN);
'+': AddKeyToList(LEX_ADD,AP_SIGN);
'=': AddKeyToList(LEX_EQ,AP_SIGN);
'>': AddKeyToList(LEX_GT,AP_SIGN);
'<': posCur := AP_LT;
'(': AddKeyToList(LEX_OPEN,AP_SIGN);
')': AddKeyToList(LEX_CLOSE,AP_START);
';': AddKeyToList(LEX_SEMI,AP_START);
'0'..'9': posCur := AP_CONST;
'A'..'Z','c','f'..'h','j'..'m',
'q'..'v','y','z','_': posCur := AP_VAR;
'{': posCur := AP_COMM;
' ',#10,#13,#9: ;
else posCur := AP_ERR;
end{case list};
end;
AP_SIGN:
begin
{ Состояние, когда может встретиться
унарный минус }
iStart := j;
iStComm := iAll-1;
case sCurStr[j] of
'b': posCur := AP_BEGIN1;
'i': posCur := AP_IF1;
'p': posCur := AP_PROG1;
'e': posCur := AP_ELSE1;
'w': posCur := AP_WHILE1;
'd': posCur := AP_DO1;
'o': posCur := AP_OR1;
'x': posCur := AP_XOR1;
'a': posCur := AP_AND1;
'n': posCur := AP_NOT1;
'-': AddKeyToList(LEX_UMIN,AP_SIGN);
'(': AddKeyToList(LEX_OPEN,AP_SIGN);
')': AddKeyToList(LEX_CLOSE,AP_START);
'0'..'9': posCur := AP_CONST;
'A'..'Z','c','f'..'h','j'..'m',
'q'..'v','y','z','_': posCur := AP_VAR;
'{': posCur := AP_COMMSG;
' ',#10,#13,#9: ;
else posCur := AP_ERR;
end{case list};
end;
AP_LT:
{ Знак меньше или знак неравенства? }
case sCurStr[j] of
'b': AddKeyToList(LEX_LT,AP_BEGIN1);
'i': AddKeyToList(LEX_LT,AP_IF1);
'p': AddKeyToList(LEX_LT,AP_PROG1);
'e': AddKeyToList(LEX_LT,AP_ELSE1);
'w': AddKeyToList(LEX_LT,AP_WHILE1);
'd': AddKeyToList(LEX_LT,AP_DO1);
'o': AddKeyToList(LEX_LT,AP_OR1);
'x': AddKeyToList(LEX_LT,AP_XOR1);
'a': AddKeyToList(LEX_LT,AP_AND1);
'n': AddKeyToList(LEX_LT,AP_NOT1);
'>': AddKeyToList(LEX_NEQ,AP_SIGN);
'-': Add2KeysToList(LEX_LT,LEX_UMIN,AP_SIGN);
'(': Add2KeysToList(LEX_LT,LEX_OPEN,AP_SIGN);
'0'..'9': AddKeyToList(LEX_LT,AP_CONST);
'A'..'Z','c','f'..'h','j'..'m','q'..'v',
'y','z','_': AddKeyToList(LEX_LT,AP_VAR);
'{': AddKeyToList(LEX_LT,AP_COMMSG);
' ',#10,#13,#9: AddKeyToList(LEX_LT,AP_SIGN);
else posCur := AP_ERR;
end{case list};
AP_ELSE1:
{ "else", или же "end", или переменная? }
case sCurStr[j] of
'l': posCur := AP_ELSE2;
'n': posCur := AP_END2;
':': AddVarToList(AP_ASSIGN,j);
'-': AddVarKeyToList(LEX_SUB,AP_SIGN);
'+': AddVarKeyToList(LEX_ADD,AP_SIGN);
'=': AddVarKeyToList(LEX_EQ,AP_SIGN);
'>': AddKeyToList(LEX_GT,AP_SIGN);
'<': AddVarToList(AP_LT,j);
'(': AddVarKeyToList(LEX_OPEN,AP_SIGN);
')': AddVarKeyToList(LEX_CLOSE,AP_START);
';': AddVarKeyToList(LEX_SEMI,AP_START);
'{': AddVarToList(AP_COMM,j);
'0'..'9','A'..'Z','a'..'k','m',
'o'..'z','_': posCur := AP_VAR;
' ',#10,#13,#9: AddVarToList(AP_START,j);
else posCur := AP_ERR;
end{case list};
AP_IF1: KeyLetter('f',AP_IF2);
AP_IF2: KeyFinish(LEX_IF);
AP_ELSE2: KeyLetter('s',AP_ELSE3);
AP_ELSE3: KeyLetter('e',AP_ELSE4);
AP_ELSE4: KeyFinish(LEX_ELSE);
AP_OR1: KeyLetter('r',AP_OR2);
AP_OR2: KeyFinish(LEX_OR);
AP_DO1: KeyLetter('o',AP_DO2);
AP_DO2: KeyFinish(LEX_DO);
AP_XOR1: KeyLetter('o',AP_XOR2);
AP_XOR2: KeyLetter('r',AP_XOR3);
AP_XOR3: KeyFinish(LEX_XOR);
AP_AND1: KeyLetter('n',AP_AND2);
AP_AND2: KeyLetter('d',AP_AND3);
AP_AND3: KeyFinish(LEX_AND);
AP_NOT1: KeyLetter('o',AP_NOT2);
AP_NOT2: KeyLetter('t',AP_NOT3);
AP_NOT3: KeyFinish(LEX_NOT);
AP_PROG1: KeyLetter('r',AP_PROG2);
AP_PROG2: KeyLetter('o',AP_PROG3);
AP_PROG3: KeyLetter('g',AP_PROG4);
AP_PROG4: KeyFinish(LEX_PROG);
AP_WHILE1: KeyLetter('h',AP_WHILE2);
AP_WHILE2: KeyLetter('i',AP_WHILE3);
AP_WHILE3: KeyLetter('l',AP_WHILE4);
AP_WHILE4: KeyLetter('e',AP_WHILE5);
AP_WHILE5: KeyFinish(LEX_WHILE);
AP_BEGIN1: KeyLetter('e',AP_BEGIN2);
AP_BEGIN2: KeyLetter('g',AP_BEGIN3);
AP_BEGIN3: KeyLetter('i',AP_BEGIN4);
AP_BEGIN4: KeyLetter('n',AP_BEGIN5);
AP_BEGIN5: KeyFinish(LEX_BEGIN);
AP_END2: KeyLetter('d',AP_END3);
AP_END3:
{ "end", или же "end.", или переменная? }
case sCurStr[j] of
'-': Add2KeysToList(LEX_END,LEX_UMIN,AP_SIGN);
'+': Add2KeysToList(LEX_END,LEX_ADD,AP_SIGN);
'=': Add2KeysToList(LEX_END,LEX_EQ,AP_SIGN);
'>': Add2KeysToList(LEX_END,LEX_GT,AP_SIGN);
'<': AddKeyToList(LEX_END,AP_LT);
'(': Add2KeysToList(LEX_END,LEX_OPEN,AP_SIGN);
')':
Add2KeysToList(LEX_END,LEX_CLOSE,AP_START);
';': Add2KeysToList(LEX_END,LEX_SEMI,AP_START);
'.': AddKeyToList(LEX_FIN,AP_START);
'0'..'9','A'..'Z','a'..'z','_':
posCur := AP_VAR;
'{': AddKeyToList(LEX_END,AP_COMMSG);
' ',#10,#13,#9: AddKeyToList(LEX_END,AP_SIGN);
else posCur := AP_ERR;
end{case list};
AP_ASSIGN:
case sCurStr[j] of
'=': AddKeyToList(LEX_ASSIGN,AP_SIGN);
else posCur := AP_ERR;
end{case list};
AP_VAR:
case sCurStr[j] of
':': AddVarToList(AP_ASSIGN,j);
'-': AddVarKeyToList(LEX_SUB,AP_SIGN);
'+': AddVarKeyToList(LEX_ADD,AP_SIGN);
'=': AddVarKeyToList(LEX_EQ,AP_SIGN);
'>': AddVarKeyToList(LEX_GT,AP_SIGN);
'<': AddVarToList(AP_LT,j);
'(': AddVarKeyToList(LEX_OPEN,AP_SIGN);
')': AddVarKeyToList(LEX_CLOSE,AP_START);
';': AddVarKeyToList(LEX_SEMI,AP_START);
'0'..'9','A'..'Z','a'..'z','_':
posCur := AP_VAR;
'{': AddVarToList(AP_COMM,j);
' ',#10,#13,#9: AddVarToList(AP_START,j);
else posCur := AP_ERR;
end{case list};
AP_CONST:
case sCurStr[j] of
':': AddConstToList(AP_ASSIGN,j);
'-': AddConstKeyToList(LEX_SUB,AP_SIGN);
'+': AddConstKeyToList(LEX_ADD,AP_SIGN);
'=': AddConstKeyToList(LEX_EQ,AP_SIGN);
'>': AddConstKeyToList(LEX_GT,AP_SIGN);
'<': AddConstToList(AP_LT,j);
'(': AddConstKeyToList(LEX_OPEN,AP_SIGN);
')': AddConstKeyToList(LEX_CLOSE,AP_START);
';': AddConstKeyToList(LEX_SEMI,AP_START);
'0'..'9': posCur := AP_CONST;
'{': AddConstToList(AP_COMM,j);
' ',#10,#13,#9: AddConstToList(AP_START,j);
else posCur := AP_ERR;
end{case list};
AP_COMM:
case sCurStr[j] of
'}': posCur := AP_START;
end{case list};
AP_COMMSG:
case sCurStr[j] of
'}': posCur := AP_SIGN;
end{case list};
end{case pos};
{ Проверяем, не достигнут ли конец строки }
if j = iStr then
begin
{ Конец строки - это конец текущей лексемы }
case posCur of
AP_IF2: AddKeyToList(LEX_IF,AP_SIGN);
AP_PROG4: AddKeyToList(LEX_PROG,AP_START);
AP_ELSE4: AddKeyToList(LEX_ELSE,AP_START);
AP_BEGIN5: AddKeyToList(LEX_BEGIN,AP_START);
AP_WHILE5: AddKeyToList(LEX_WHILE,AP_SIGN);
AP_END3: AddKeyToList(LEX_END,AP_START);
AP_OR2: AddKeyToList(LEX_OR,AP_SIGN);
AP_DO2: AddKeyToList(LEX_DO,AP_SIGN);
AP_XOR3: AddKeyToList(LEX_XOR,AP_SIGN);
AP_AND3: AddKeyToList(LEX_AND,AP_SIGN);
AP_NOT3: AddKeyToList(LEX_AND,AP_SIGN);
AP_LT: AddKeyToList(LEX_LT,AP_SIGN);
AP_FIN: AddKeyToList(LEX_FIN,AP_START);
AP_CONST: AddConstToList(AP_START,j+1);
AP_ASSIGN: posCur := AP_ERR;
AP_IF1,AP_PROG1,AP_PROG2,AP_PROG3,
AP_ELSE1,AP_ELSE2,AP_ELSE3,AP_XOR1,AP_XOR2,
AP_OR1,AP_DO1,AP_AND1,AP_AND2,AP_NOT1,AP_NOT2,
AP_WHILE1,AP_WHILE2,AP_WHILE3,AP_WHILE4,
AP_END2,AP_BEGIN1,AP_BEGIN2,AP_BEGIN3,AP_BEGIN4,
AP_VAR: AddVarToList(AP_START,j+1);
end{case pos2};
end;
{ Проверяем не была ли ошибка в лексемах }
if posCur = AP_ERR then
begin
{ Если была ошибка, вычисляем позицию
ошибочной лексемы }
iStart := (j - iStart)+1;
{ и запоминаем ее в виде фиктивной лексемы в начале
списка для детальной диагностики ошибки }
listLex.Insert(0,
TLexem.CreateInfo('Недопустимая лексема',
iAll-iStart,i,iStart));
{ Если ошибка, прерываем цикл }
Break;
end;
end{for j};
{ В конце строки увеличиваем общий счетчик символов
на 2: конец строки и возврат каретки }
Inc(iAll,2);
{ Если ошибка, запоминаем номер ошибочной строки
и прерываем цикл }
if posCur = AP_ERR then
begin
Result := i+1;
Break;
end;
end{for i};
{ Если комментарий не был закрыт, то это ошибка }
if posCur in [AP_COMM,AP_COMMSG] then
begin
listLex.Insert(0,
TLexem.CreateInfo('Незакрытый комментарий',
iStComm,iCnt,iAll-iStComm));
Result := iCnt;
end
else
if not (posCur in [AP_START,AP_SIGN,AP_ERR]) then
{ Если КА не в начальном состоянии -
это неверная лексема }
begin
listLex.Insert(0,
TLexem.CreateInfo('Незавершенная лексема',
iAll-iStart,iCnt,iStart));
Result := iCnt;
end;
end;

end.
Соседние файлы в папке Cursov