Книга: Системное программное обеспечение. Лабораторный практикум

Листинг П3.5. Заполнение таблицы лексем по исходному тексту программы

Листинг П3.5. Заполнение таблицы лексем по исходному тексту программы

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; { Обнуляем результат функции }

posCur:= AP_START;{Устанавливаем начальное состояние КА}

iStComm:= 0; 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};

Inc(iAll,2); { В конце строки увеличиваем общий счетчик

cимволов на 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.

Оглавление книги


Генерация: 1.226. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз