Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #67, ИЮЛЬ 2004 г.

Интерпретируй ЭТО!

Диман Dr.X (xdiman@mail.ru)

Xakep, номер #067, стр. 067-086-4


procedure parser(inp:string; var func,param1,param2,param3:string);

в параметре var func: string возвращает не строку (имя_функции), а код операции (КОП) типа Integer. Для перевода имени функции в соответствующий КОП я использую чудный объект TStringList, его свойство Objects и быстрый метод IndexOf. Для простоты его экземпляр можно объявить глобально, например:

Объявляем экземпляр

unit uCommands;

interface

uses Classes;

var Commands: TStringList;

implementation

procedure MakeCommandList;

begin

with Commands do

begin

AddObject('GOLINE' , Pointer($80));

AddObject('GOCHAR' , Pointer($01));

AddObject('INSERT' , Pointer($02));

AddObject('REPLACE' , Pointer($83));

AddObject('FIND' , Pointer($04));

AddObject('END' , Pointer($85));

AddObject('HOME' , Pointer($86));

AddObject('DELBEFORE', Pointer($07));

AddObject('DELAFTER' , Pointer($08));

end;

// Коды операции даны вразброд, чтобы показать на примере

// использование свойства Objects, а не порядкового номера.

end;

initialization

Commands:= TStringList.Create;

MakeCommandList;

finalization

Commands.Free;

end;

Заметь, что список создается один раз. Теперь из процедуры

parser можно смело сделать функцию. Эта функция будет возвращать в

параметре func искомый КОП функции, прочитанной из входного

параметра inp. Если функция вернет True, значит, строка пропарсена

корректно; если False – значит, прочитано имя функции, которой нет в списке

Commands, т.е. возникла ошибка "неизвестный идентификатор".

Парсер

function parser(inp: string; var func: Integer;

var param1, param2, param3: string): Boolean;

var

i, a: integer;

sFunc: string; // Имя функции, которое прочитали

Index: Integer; // Порядковый номер имени прочитанной функции

// в списке Commands.

begin

Result:= False;

a:= 1;

while pos(' ', inp) < 0 do

begin

i:= pos(' ', inp);

case a of

1: begin

sFunc:= copy(inp, 1, i - 1); // Получаем имя функции

Index:= Commands.IndexOf(sFunc); // Получаем номер функции

// Если функции нет в списке, то Index будет равен -1.

Result:= Index < -1;

if Result //Если функция найдена, возвращаем ее КОП

then func:= Integer(Commands.Objects[Index])

else Exit; //иначе физкульт-привет - и на выход

end;

2: param1:= copy(inp, 1, i - 1);

3: param2:= copy(inp, 1, i - 1);

4: param3:= copy(inp, 1, i - 1);

end;

Inc(a);

inp:= copy(inp, i + 1, length(inp) - i);

end;

if a = 2 then param1:= inp;

if a = 3 then param2:= inp;

if a = 4 then param3:= inp;

end;

С учетом этого можно переделать изначальный кусок таким образом:

Проверяем данные

...

var func: Integer;

while not EOF(fin) do

begin

readln (fin, temp);

if parser(temp, func, param1, param2, param3)

then case func of

$80: { GOLINE } ;

$01: { GOCHAR } ;

$02: { INSERT } ;

$83: { REPLACE } ;

$04: { FIND } ;

$85: { END } ;

$86: { HOME } ;

$07: { DELBEFORE } ;

$08: { DELAFTER } ;

end //case

else begin

ShowMessage('Ты что ввел, уважаемый?');

Break;

end;

end;

Недоделки

Редактор этот, как и любые великие программы :), не лишен багов. Во-первых, во всех функциях, использующих строковые параметры, нельзя использовать строку, содержащую пробелы. Иначе обработчик посчитает оставшуюся часть отдельным параметром. Во вторых, он не позволяет добавлять переменные, циклы, условия и т.д. В общем, огромный простор для творчества ;).

Назад на стр. 067-086-3  Содержание  Вперед на стр. 067-086-5