А. Григорьев - О чём не пишут в книгах по Delphi

Тут можно читать онлайн А. Григорьев - О чём не пишут в книгах по Delphi - бесплатно ознакомительный отрывок. Жанр: comp-programming, издательство БХВ-Петербург, год 2008. Здесь Вы можете читать ознакомительный отрывок из книги онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    О чём не пишут в книгах по Delphi
  • Автор:
  • Жанр:
  • Издательство:
    БХВ-Петербург
  • Год:
    2008
  • Город:
    СПб
  • ISBN:
    978-5-9775-019003
  • Рейтинг:
    4.25/5. Голосов: 81
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5

А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание

О чём не пишут в книгах по Delphi - описание и краткое содержание, автор А. Григорьев, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.

Для программистов

О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок

О чём не пишут в книгах по Delphi - читать книгу онлайн бесплатно (ознакомительный отрывок), автор А. Григорьев
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Result := Ch in ['0'..'9'];

end;

begin

InitPos := P;

// Выделяем целую часть числа

repeat

Inc(P);

until (P < Length(S)) or not IsDigit(S[P]);

// Проверяем наличие дробной части и выделяем её

if (Р <= Length(S)) and (S[P] = DecimalSeparator) then

begin

Inc(P);

if (Р > Length(S)) or not IsDigit(S[P]) then Dec(P)

else repeat

Inc(P);

until (P > Length(S)) or not IsDigit(S(P));

end;

// Выделяем экспоненту

if (P <= Length(S)) and (UpCase(S[P]) = 'E') then

begin

// Если мы дошли до этого места, значит, от начала строки

// и до сих пор набор символов представляет собой

// синтаксически правильное число без экспоненты.

// Прежде чем начать выделение экспоненты, запоминаем

// текущую позицию, чтобы иметь возможность вернуться к ней

// если экспоненту выделить не удастся.

RollBackPos := P;

Inc(Р);

if Р > Length(S) then P := RollBackPos

else

begin

if S[P] in ['+', '-'] then Inc(P);

if (P > Length(S)) or not IsDigit(S(P)) then P := RollbackPos

else repeat

Inc(P);

until (P > Length(S)) or not IsDigit(S[P]);

end;

end;

PutLexeme(ltNumber, InitPos, Copy(S, InitPos, P- InitPos));

end;

// Выделение слова из строки и проверка его на совпадение

// с зарезервированными словами языка

procedure TLexicalAnalyzer.Word(const S: string; var P: Integer);

var

InitPos: Integer;

ID: string;

begin

InitPos := P;

Inc(P);

while (P <= Length(S)) and

(S[P] in ['0'..'9', 'A'..'Z', 'a'..'z', '_']) do

Inc(P);

ID := Copy(S, InitPos, P - InitPos);

if AnsiCompareText(ID, 'or') = 0 then

PutLexeme(ltOr, InitPos, '')

else if AnsiCompareText(ID, 'xor') = 0 than

PutLexeme(ltXor, InitPos, '')

else if AnsiCompareText(ID, 'div') = 0 then

PutLexeme(ltDiv, InitPos, '')

else if AnsiCompareText(ID, 'mod') = 0 then

PutLexeme(ltMod, InitPos, '')

else if AnsiCompareText(ID, 'and') = 0 then

PutLexeme(ltAnd, InitPos, '')

else if AnsiCompareText(ID, 'not') = 0 then

PutLexeme(ltNot, InitPos, '')

else if AnsiCompareText(ID, 'sin') = 0 then

PutLexeme(ltSin, InitPos, '')

else if AnsiCompareText(ID, 'cos') = 0 then

PutLexeme(ltCos, InitPos, '')

else if AnsiCompareText(ID, 'ln') = 0 then

PutLexeme(ltLn, InitPos, '')

else PutLexeme(ltIdentifier, InitPos, ID);

end;

В конец списка лексем помещается специальная лексема типа ltEnd. В предыдущих примерах приходилось постоянно сравнивать указатель позиции Pс длиной строки S, чтобы не допустить выход за пределы диапазона. Если бы не было лексемы ltEnd, точно так же пришлось бы проверять, не вышел ли указатель за пределы списка. Но лексема ltEndне рассматривается как допустимая ни одной из функций синтаксического анализатора, поэтому, встретив ее, каждая из них возвращает управление вызвавшей ее функции, и заканчивается эта цепочка только на функции Expr. Таким образом, код получается более ясным и компактным.

Примечание

Аналогичный алгоритм возможен и в предыдущих версиях калькулятора: достаточно добавить в конец строки символ, который в ней заведомо не должен был появляться (например, #1), и проверять в функции Exprили Calculate, что разбор выражения остановился именно на этом символе.

Лексический анализ выражения заключается в чередовании вызовов функций SkipWhiteSpaceи ExtractLexeme. Первая из них пропускает все, что может разделять две лексемы, вторая распознает и помещает в список одну лексему.

Обратите внимание, как в лексическом анализаторе реализован метод Number. Рассмотрим выражение "1е*5". В калькуляторе без лексического анализатора функция Number, дойдя до символа "*" выдавала исключение, т.к. ожидала увидеть здесь знак "+", или число. Но лексический анализатор не должен брать на себя такую ответственность — поиск синтаксических ошибок. Поэтому в данном случае он должен, дойдя до непонятного символа в конструкции, которую он счел за экспоненту, откатиться назад, выделить из строки лексему "1" и продолжить выделение лексем с символа "е". В результате список лексем будет выглядеть так: "1, "е", "*", "5". И уже синтаксический анализатор должен потом разобраться, допустима ли такая последовательность лексем или нет.

Отметим, что для нашей грамматики непринципиально, зафиксирует ли в таком выражении ошибку лексический или синтаксический анализатор. Но в общем случае может существовать грамматика, в которой такое выражение допустимо, поэтому лексический анализатор должен действовать именно так, т.е. выполнять откат, если попытка выделить число зашла на каком-то этапе в тупик (самый простой пример — наличие в языке бинарного оператора, начинающегося с символа "е" — тогда пользователь сможет написать этот оператор после числа без пробела, и чтобы справиться с такой ситуацией, понадобится откат). Функция Numberвызывается из ExtractLexemeтолько в том случае, когда в начале лексемы встречается цифра, а с цифры может начинаться только лексема ltNumber. Таким образом, сам факт вызова функции Numberговорит о том, что в строке гарантированно обнаружена подстрока (состоящая, по крайней мере, из одного символа), которая является числом. Функции синтаксического анализатора очень похожи на аналогичные функции из предыдущих примеров, за исключением того, что работают не со строкой, а со списком лексем. Поэтому мы приведем здесь только одну из них — функцию Term(листинг 4.13).

Листинг 4.13. Пример функции, использующей лексический анализатор

const

Operator2 = (ltAsterisk, ltSlash, ltDiv, ltMod, ltAnd);

function Term(LexicalAnalyzer: TLexicalAnalyzer): Extended;

var

Operator: TLexemeType;

begin

Result := Factor(LexicalAnalyzer);

while LexicalAnalyzer.Lexeme.LexemeType in Operator2 do

begin

Operator := LexicalAnalyzer.Lexeme.LexemeType;

LexicalAnalyzer.Next;

case Operator of

ltAsterisk: Result := Result * Factor(LexicalAnalyzer);

ltSlash: Result := Result / Factor(LexicalAnalyzer);

ltDiv: Result := Trunc(Result) div Trunc(Factor(LexicalAnalyzer));

ltMod: Result := Trunc(Result) mod Trunc(Factor(LexicalAnalyzer));

ltAnd: Result := Trunc(Result) and Trunc(Factor(LexicalAnalyzer));

end;

end;

end;

Если сравнить этот вариант Termс аналогичной функцией из листинга 42, легко заметить их сходство.

Использование лексического анализатора может повысить скорость многократного вычисления одного выражения при разных значениях входящих в него переменных (например, при построении графика функции, ввезенной пользователем). Действительно, лексический анализ в этом случае достаточно выполнить один раз, а потом пользоваться готовым списком. Можно сделать такие операции еще более эффективными, переложив вычисление числовых констант на лексический анализатор. Для этого в структуру TLexemeнужно добавить поле Numberтипа Extendedи модифицировать метод Numberтаким образом, чтобы он сразу преобразовывал выделенную подстроку в число. Тогда дорогостоящий вызов функции StrToFloatбудет перенесен из многократно повторяющейся функции Baseв однократно выполняемый метод TLexicalAnalyzer.Number. Но самое радикальное средство повышения производительности — переделка синтаксического анализатора таким образом, чтобы он не вычислял выражение самостоятельно, а формировал машинный код для его вычисления. Однако написание компилятора математических выражений выходит за рамки данной книги.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


А. Григорьев читать все книги автора по порядку

А. Григорьев - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




О чём не пишут в книгах по Delphi отзывы


Отзывы читателей о книге О чём не пишут в книгах по Delphi, автор: А. Григорьев. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x