Написание простого DSL компилятора на Delphi (1. Язык)

Перевод поста Writing a Simple DSL Compiler with Delphi (1. The Language).

Эта статья представляет собой неформальное описание простого языка (далее я называю его "Язык") для которого я пишу компилятор. Если вы только начинаете читать эту серию, то я бы рекомендовал вам начать с этого поста.

Давайте начнём с простого примера который вычисляет i-тое число Фибоначчи

Код довольно прост. Первые два числа в последовательности Фибоначчи это единицы, а последующие являются суммой двух предыдущих числе в последовательности.

Следующие правила описывают язык (более или менее):

  • Язык относится к категории C-подобных языков.
  • Пробелы игнорируются.
  • Только один тип данных — целое число (integer)
  • Только три оператора: +, -, и <.
  • a < b возвращает 1 если a меньше чем b, и 0 в противоположном случае.
  • Только два оператора if и return.
  • Оператор if выполняет блок then если условное выражение не равно 0 и выполняет блок else в противном случае. Блок else обязателен.
  • Оператор return только устанавливает результат функции и не прерывает поток управления.
  • Нет оператора присваивания.
  • Каждая функция возвращает integer.
  • Параметры всегда передаются по значению.
  • Функции без оператора return возвращают 0.
  • Функции могут вызывать другие функции (или себя рекурсивно).

Как вы можете видеть, Язык ужасно ограничен, но в нем достаточно функционала для простых примеров. Язык также является функциональным, в терминах computer science. Мы будем использовать это в наших интересах намного позже в этой серии.

Немного более формальное (но всё ещё очень неформальное) описание синтаксиса:

Написание простого DSL компилятора на Delphi (0. Введение)

Перевод поста Writing a Simple DSL Compiler with Delphi (0. Introduction)

Некоторое время назад я слушал подкаст Hanselminutes (YOU should write an interpreter with Thorsten Ball) где парень описал как он написал простой интерпретатор на языке Go. В действительности, меня не очень интересовало написание интерпретатора — я уже делал это однажды — но мысль закралась мне в голову. Я спросил себя смогу ли я сделать что-то лучше — написать компилятор (или что-то похожее на компилятор, как вы увидите дальше).

То что я хотел сделать — это взять простой язык, распарить его, сгенерировать абстрактное синтаксическое дерево и затем конвертировать его в одну большую анонимную функцию вызывающую другие анонимные функции, которые вызывают другие анонимные функции и так далее. Это сложно объяснить, так что позвольте мне показать очень простой пример.

Скажем, у меня есть простоя программа написанная на моём языке которая складывает два числе вместе

Читать далее Написание простого DSL компилятора на Delphi (0. Введение)

Доклады KnowledgeConf 2019 про ведение конспектов

На конференции KnowledgeConf 2019 в основном были доклады связанные с управлением знания в организации, но были и два доклада связанных с управлением личными знаниями и конспектами. Они показались мне доволльно интересными.

Видео с конференции в открытом доступе сейчас нет, они будут открыты через несколько месяцев. Но по конспектам, ссылки на которые указаны ниже, можно понять основные положения докладов и куда дальше копать.

Применение практик Тиаго Форте для управления своими знаниями

Проблема: как обеспечить быстрое восстановление в голове знаний о различных областях знаний или проектах. Информации много, требуется редко, но когда требуется важно восстановить в голове основные моменты очень быстро.

Можно попробовать

  • Вести блог
  • Конспектировать
  • Копировать цита

Недостатки у всех этих способов:

  • Требуют много времени
  • Нет возможности быстро посмотреть расширенный контекст, а если и смотреть его то вариант только один — смотреть оригинал, что долго и не удобно.

Тиаго Форте предлагает для этого следующее решение:

  • Всю требуемую информацию хранить на ПК
    • ПО может быть разным, главное чтобы было удобно и быстро добавлять, редактировать и искать информацию.
  • Сохранять оригинал документа (книги, статьи и т.п.)
  • Сверху оригинала делать несколько слоев
    • Выделение в тексте (цветом, шрифтом и т.п.) ниболее важной информации
    • Выделение в ещё более важной информации из важной информации
    • Отдельно выжимка из этих выделений

Смысл этих выделений чтобы обеспечить быстрое распознавание (узнавание, вспоминание) изученного материала. Вместо чтения материала целиком читаются только фрагменты и в памяти всплывают остальные моменты. Основные отличия от традиционных методов в том что активно используются возможности современного ПО и есть возможно просмотреть не только выжимку (ключевые слова или конспект), а быстро и удобно спустится на более полный слой, а при необходимости и дальше до самого оригинала.

Описание и презентация.

Как я 15 лет делал себе персональную Wiki для программиста

Описана разработка синтаксиса и подсветки для файлов с конспектами, в особенности для конспектов которые содержат много кусков кода. Сами файлы хранятся в Git.

Послушать было довольно интересно. Хотя практически, как мне кажется, удобнее применять распространённые языки лёгкой разметки. Это более переносимо, независимо от платформы и требует меньше времени. Возможно, ценой того что их нельзя настроить под себя. Я использую markdown и редактор Typora.

Описание и презентация.

XMind — программа для создания интеллект-карт

Я попробовал несколько программ для создания интеллект-карт и уже довольно долгое время пользуюсь XMind.

Пользуюсь в основном двумя функциями:

  • Собственно само создание интеллект-карт. Удобный интерфейс, большую часть действий можно сделать с клавиатуры. Много дополнительных возможностей: стрелки, группировки узлов, форматирование и другие.
  • Экспорт ИК в изображение.

Так возможностей мне требуется не сильно много. то хватает бесплатной версии.

Можно использовать словари для проверки орфографии, но предлагаемый словарь страдает нехваткой многих слов. Как я понял в качестве словаря можно подключить только простой текстовый файл со списком слов, Hunspell и подобное не поддерживается, так что чего-то особенного ожидать нельзя.

Пример ИК для главы книги экспортированной через XMind

Интеллект-карта. Ощущения
Ощущения

Средства для автоматического форматирования кода Delphi

Несколько лет назад я зафиксировал на GitHub (GitBook) описание правил форматирования кода принятых в компании где я работаю. Описание не дописано, но часть со ссылками на форматеры кода для Delphi может быть кому-то полезна. Мне удалось найти только три которые более-менее развивались. Вроде, с того времени чего-то нового не появилось.

JEDI Code Format

JEDI Code Format - отдельное приложение для форматирования исходных кодов Object Pascal и Delphi.

Experimental GExperts Version

Это экспериментальная версия эксперта для IDE RAD Studio GExpert.

Поддерживаемые версии IDE: 6, 7, 2005, 2006, 2007, 2009, 2010, XE1, XE2.

Стандартное форматирование кода в Delphi 2010

Начиная с Delphi 2010 в IDE добавлено стандартное средство для автоматического форматирования исходного кода.

Использование пустого блока try…except в Delphi

Есть несколько доводов чтобы никогда не использовать пустой блок try...except, такой как

А причин чтобы применять такую конструкцию мне найти не удалось.

1. Исключения для исключений, не для логики

Исключения нужны для непредвиденных ситуаций. Если ситуация рассматривается как ожидаемая или вероятная, то нужно использовать обычные условия.

Например, если файл который открывает программа всегда находится в требуемом месте и нет причин ожидать что его не будет, то проверку можно организовать через исключения. Если же файл может переместить пользователь и логика работы программы допускает или позволяет это сделать, то обработка должна быть организована другими средствами — не исключениями.

Следовательно, блокирование исключения не имеет смысла. Если какая-то проблема предполагалась, то надо обработать её через условия. Если возможны какие-то исключения и их нужно обрабатывать, то должен быть какой-то код в внутри except. Если же не первое не второе то зачем этот пустой блок?

2. Трудности с отладкой

Сокрытие ошибки без сообщения затрудняет поиск проблемы. Программа просто ведёт себя не так как ожидается, никакого сообщения нет, что смотреть в первую очередь непонятно. Если бы выходило исключение то проблемное место было бы проще найти (например при использовании EurekaLog), была бы хоть какая-то информация о проблеме.

3. Временное решение

Предположим, появляется ошибка причина которой непонятна. Участок кода не критичен и чтобы её скрыть применяется такая конструкция.

Такой подход допустим временно, если ситуация критичная и нужно срочно решить проблему. Но это именно временное решение. Дальше всё равно нужно разобраться и исправить корень проблемы. Если этого не сделать, то не решённая должным образом проблема может проявиться и другим способом. А для получения дополнительной информации, чтобы было проще искать проблему, можно например использовать логирование в блоке except, вместо того чтобы оставлять его пустым.

4. Запись в лог

Даже если это действительно какая-то особая ситуация, то можно как минимум записать это в лог и потом решить что делать. Ситуация не останется незамеченной, при любом странном поведении можно будет просмотреть этот лог.

SQL Injection в Delphi

Перевод поста SQL Injection

Я понял, что в своём недавнем посте security assumptions пропустил одно важное предположение (сейчас это исправлено):

Предполагайте, что все входные данные могут быть вредоносными.

Сегодня я хочу показать очень общую ошибку, которая может возникнуть во всех языках и SQL базах данных, и то как её можно использовать. Эта ошибка называется внедрение SQL кода. Я слышал, что разработчики предполагают что эта проблема связана только с web-приложениями. Но я видел эту проблему во всех типах приложений которые работают с базой данных.

Сегодняшний пример является VCL приложением использующим FireDAC для доступа к SQLite. Пример можно найти в репозитории security-demo на GitHub.

Внедрения SQL имеют место когда вы не используете параметры, из-за этого входные данные имеют возможность изменять вашу команду SQL.

Ниже показан небезопасный путь передать значение из поля ввода в запрос

Если я введу следующий текст в edtSearchTerm.text

То я получу список таблиц в база данных, в котором просто увидеть другую таблицу с названием salary. Затем я могу ввести следующее и получить всю информацию об оплате.

Ниже показан безопасный способ сделать туже функцию

Теперь я могу снова попытаться произвести внедрение SQL с помощью тех-же строк. И это мне не удаться, так как строки теперь внутри параметра и следовательно не могут изменить оператор SQL. Проблемы легко избежать, но всё же это довольно распространённая ошибка.

Тестирование на внедрения SQL кода очень простое — вы пробуете завершить ввод одиночной или двойной кавычкой. Если вы получаете неожиданные ошибки то у вас есть возможность SQL Injection.

Мы склонны концентрироваться на вводе от пользователя, но API такие как SOAP или REST также могут стать целью SQL Injection. Поэтому я очень осторожно сказал что нужно проверять все входные данные, а не только ввод пользователя.

Статьи про Delphi c softwarer.ru

Довольно давно существовал сайт Александра Просторова со статьями про Delphi softwarer.ru, Сейчас он не работает. Часть статей можно найти через web.archive.org, но это не очень удобно. Я скачал наиболее полезные, на мой взгляд, и сохранил в архив.

Из них самые лучше первые три:

Run-time packages.

В статье рассказано о том как и зачем применять пакеты времени выполнения.

Работа с динамической памятью.

Подробно разобрана тема создания и уничтожения объектов. Включая использования try...finnaly, концепции владения и нотификации в VCL, создание и уничтожение форм.

Применение модулей данных в немодальном интерфейсе.

Описано решение проблемы связывания модуля данных и нескольких экземпляров формы.

Остальные статьи:

  • Принципы Delphi.
  • Crack-классы.
  • Разнесение design- и runtime свойств.
  • История одной оптимизации.
  • Макрокомпоненты.
  • О сериализации множеств.
  • Обработчики событий.
  • Ошибки интерфейса.
  • Подробности Oracle.
  • Подсказки по использованию Delphi.
  • Расстановка TabOrder-ов.
  • Реализация синглтонов.
  • Таймеры.

Проблемы перегрузки операторов в Delphi

Вольный перевод поста On the operator overloading in Delphi.

Перегрузка операторов в Delphi является простой если запись не содержит в себе полей-ссылок на объекты в куче. Чтобы проиллюстрировать эту проблему рассмотрим следующий (некорректный!) пример:

Читать далее Проблемы перегрузки операторов в Delphi

Программирование в функциональном стиле в Delphi

Вольный перевод поста Functional programming style in Delphi.

Парадигма функционального программирования находит свой путь даже в Delphi — императивном языке без сборщика мусора. Рассмотрим следующий пример кода, который меняет заголовок кнопки используя расширенный RTTI (требуется версия Delphi 2010 или выше).

При анализе этого кода обратите внимание на следующее:

  • Тип TRttiContext - запись (record); вам не нужно создавать и уничтожать переменную с типом запись в том виде как это делается для объектов.
  • TRttiProperty и TRttiType - классы; Экземпляры этих классов создаются соответствующими методами классов TRttiType и TRttiContext, но вам не нужно уничтожать их самостоятельно — лежащая в основе них расширенная реализация RTTI заботится об этом сама.

В результате код может переписан в функциональном стиле:

Все переменные стали не нужны и нет утечек памяти.