RUSSIAN
(Русский)
ENGLISH


Эта функция использует куки.
Если браузер не принимает куки,
используется светлая тема.

ЧАСТЬ 1.   AL-IV:   Как начать программировать

 

 

Ссылка на загрузку компиляторов и базовых примеров кода:
 https://sourceforge.net/projects/al-iv/

 

Дата последнего изменения: Апрель 2021
 

Выбор компилятора и целевой платформы

  • Программа на AL-IV предполагается быть максимально многоплатформенной. Написанную программу всегда можно собрать для любой поддерживаемой платформы, выбрав соответствующий компилятор и указав соответствующие библиотеки, реализующие поддержку требуемой платформы.

    Соответственно, выбор платформы не имеет значения - выбирайте ту платформу, на которой вы сейчас находитесь, и для которой имеется компилятор (Windows ?)*.
     
  • На данный момент имеются компиляторы для Delphi32, C#, Java, Free Pascal.

     
  • Таким образом, в качестве целевой платформы с удовольствием выступит любая платформа из списка: Windows(.NET/Win32/Win64), Linux, Android (на февраль 2020 - с тех пор пока изменений нет, и не ожидается).

 

 

 

Настройка параметров для компилятора

  • Компилятор из AL-IV - это консольная программа. На входе он получает указанный исходный файл, список файловых директорий для поиска используемых классов и другие параметры, а на выходе формирует выходной проект на том целевом языке программирования, для которого данная конкретная версия компилятора предназначена.
    Например, имеются компиляторы:

     

    • Compiled\AL4Compiler.exe - первичный компилятор в C#;
    • CSharpBuild\AL4CSharpCompiler.exe - компилятор в C#;
    • Delphi_build\AL4DelphiCompiler.exe - компилятор в Delphi/Free Pascal (сам на C#, требует .NET Framework 3.5);
    • By_Delphi_build\AL4DelphiCompiler.exe - компилятор в Delphi (сам скомпилирован на Delphi, соответственно, может быть запущен на ранних версиях Windows, не имеющих необходимого .NET Framework или возможности его установить. При необходимости, под wine этот компилятор может быть запущен на Linux).
  • Для того, чтобы увидеть, какие параметры и опции необходимы компилятору, можно запустить его без параметров. Он выдаст в консоли очень краткий перечень возможных ключей. Обратите внимание на ключ
    /@ путь\имя_файла
    Это лучший способ раз и навсегда настроить набор опций для компиляции вашего проекта, затем просто передавая ему файл с этими настройками как параметр.
    Если вы посмотрите в целевых директориях различных проектов файлы, имеющие необычно длинные расширения, например, compiler.options или visual-program1cs.config, то вы увидите, что это не что иное, как текстовые файлы с опциями для запуска компилятора.
     
 
  • Типичный файл с опциями будет иметь несколько строк.

    Первая строка содержит путь\имя_главного_файла - этот файл содержит корневой класс, с которого и начинается компиляция (а в последующем - и выполнение программы), он же должен содержать статическую функцию с кратким именем Main (полное имя может быть любым, например, Main|_artifical_intellect_constructor). Эта функция (без параметров и возвращаемого значения) будет вызвана для выполнения в откомпилированной программе.

    Скорее всего, будет использоваться не только один этот класс, и надо использовать один или несколько ключей
    /src путь
    для того, чтобы задать папки для поиска используемых классов. Важный момент: папки должны полностью соответствовать выбранной целевой платформе. Так, папки с именем _Delphi обычно содержат варианты классов для формирования конечной Delphi-программы, тогда как папки _CSharp содержат варианты тех же классов, но для использования при построении C#-проекта.

    Обратите внимание на опцию /nocon|sole - её следует использовать, если требуется программа с ГПИ (графическим пользовательским интерфейсом, и не нужно открывать консольное окно). В некоторых целевых платформах это не ограничивает программу в плане вывода в консоль: при выполнении соответствующих операторов в коде консоль откроется автоматически, даже и при наличии такой опции. В других целевых платформах открытие консоли на лету невозможно, и весь вывод в консоль пропадёт. Старайтесь не использовать консольный вывод в программе, если уже выбрали графический интерфейс, или не используйте опцию /noconsole - пусть открывается и консоль тогда уже.
     
 
 

Подготовка исходного кода

  • Вы можете использовать любой удобный для вас текстовой редактор для подготовки исходного кода на языке AL-IV. Например, notepad или Notepad++. Или другой аналогичный инструмент. IDE какого-нибудь языка так же вполне годится (например, Delphi или MS VC++). Кстати, здесь можно скачать xml-файл с настройками раскраски языка AL4 в Notepad++.
    Кроме того, имеется собственный редактор кода, IDE AL4. Он учитывает особенности синтаксиса языка AL4, и обеспечивает цветовую раскраску, выделение блоков линиями, подчеркивание проблемных участков кода, навигацию по коду, и т.д. В нем есть так же визуальный дизайнер форм, меню и печатных отчетов.
  • Желательно при использовании стороннего редактора кода, чтобы он понимал кодировку UTF-8. На данный момент все имеющиеся компиляторы ( изготовленные компилятором C#, Java или Delphi), понимают текст, сохранённый в такой кодировке. Но компилятор на основе выходного текста на Delphi может споткнуться на национальных символах. Лучший вариант - на первых порах национальные символы не использовать.
  • Рекомендую в настройках вашего редактора включить замену табуляций пробелами (это упростит переход от одного редактора к другому), и при возможности, использовать smart индентацию - по следующему непробельному слову (в отличие от фиксированных отступов). И, по крайней мере, не использовать слишком малые отступы (менее трёх пробелов).
  • Примеры исходного кода лучше всего изучать в кратком изложении основ языка AL-IV на примерах. Там, кстати, есть и версия программы Hello, world.
  • В случае ГПИ-программы возьмите за основу тестовый проект (папка AL4\Test_visual_project). В этом случае удобно главный класс задавать как наследника класса {Form}, помещая внутрь него статическую функцию Main, которая создаёт экземпляр главной формы, и запускает проект. Или воспользуйтесь мастером создания проектов в IDEAL4: меню Файл - Новый класс, затем Файл - Новый проект (на основе этого класса).
  • Советы по стилю оформления кода:
    • Не игнорируйте требования языка по оформлению качественного кода. Никогда не прописывайте BAD в качестве модификатора класса, всегда обеспечивайте правила:
      • не более трёх явных параметров функции,
      • не более трёх уровней вложенности CASE/FOR,
      • не более 7 простых + 7 блочных операторов в секции кода,
      • не более 7 деклараций полей в секции класса подряд.
    • Давайте переменным (функциям, типам и т.п.) внятные полные имена, используя в качестве сокращённого варианта приемлемый начальный отрезок этого имени. Вам придётся только один раз написать это длинное имя - и дальше пользуйтесь коротким на здоровье, но и через год, прочитав это длинное имя, вы (или даже не вы) сможет понять, для чего оно нужно.
    • Следуйте джентльменским соглашениям при присваивании имён функциям, их параметрам, полям и классам. Начальная часть имени должна быть читабельна (не используйте скрщния путём опускания нектрх бкв. Вместо этого предпочтительно давать имена вроде сокр|ащения, нек|отрых, бук|в). Не используйте трудночитаемые (хотя и распространившиеся) слепленныеВоединоИмена. Используйте символы_подчёркивания_в_идентификаторах, поверьте - такие имена более читабельны. Обратите внимание на возможность вставки подчёркиваний при записи длинных числовых констант: 0x_FFfe_BF2a.

 

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

 

Запуск компилятора, анализ ошибок

  • Поместите основную команду для запуска компилятора (с параметром /@ ...) в cmd-файл, чтобы не вбивать её постоянно.
  • Запускать компилятор вам придётся очень часто.
  • Ошибок у вас будет много, особенно в начале: AL-IV имеет несколько отличные от других языков синтаксис и семантику.
  • Вы использовали функцию из другого класса, и она не найдена компилятором? Проверьте, что вы включили этот класс в список импорта.
    Включили? Проверьте, что вы правильно вызываете эту функцию. Может быть, просто опечатка и не тот регистр буквы?
    Может, быть функция не статическая, и нужен экземпляр класса (вызов в форме object.Method(...) ?). Или наоборот, вы определили новую функцию, но не сделали её статической? Будьте внимательны, пожалуйста: компилятор не имеет телепатических способностей (хотя и старается).
  • Компилятор требует точку после ';', хотя код функции ещё не окончен? Проверьте: где-то выше по коду у вас лишняя ';'.
  • Компилятор считает, что точку ставить рано, или ожидает ключевое слово, а у вас '.' ? Где-то выше, вы забыли завершить блок символом ';'.
  • Компилятор ругается, что уровней вложенности более 3, а вы наблюдаете только 3 уровня? Проверьте, что выше по тексту все символы ';' на своих местах.
  • Записывайте символ ';', который пришлось перенести на следующую строку - точно под тем оператором, который он завершает.
    FOR ... ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
        PUSH ... ▄▄▄▄▄▄▄▄▄▄▄▄▄ 
             CASE ... ▄▄▄▄▄▄  
                  ... ; ▄▄▄█  
        ; ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█ 
    ; ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█

  • Часто ошибаетесь с этими ';'/'.' ? В качестве упражнения напишите утилиту, которая расставит уровни вложенности для всех операторов в исходном коде. Например, для заданной функции в исходном тексте. Практика кодирования полезна и - полезна: эта утилита пригодится вам в следующий раз, когда вы столкнётесь с такой ошибкой.
  • Наконец, используйте специализированный редактор IDE AL4, который цветными линиями подтвердит правильный порядок подчиненности вложенных операторов еще до запуска компилятора.
  • После того, как компилятор AL-IV успешно (наконец!) соберёт файлы целевого проекта на выходном языке, он попытается запустить компилятор соответствующего языка.
    • С компилятором C# вряд ли будут проблемы - он устанавливается по стандартному пути вместе с установкой .NET фреймворка (csc.exe);
    • Для запуска компилятора Delphi32 вам понадобится dcc32.exe от любого из старых компиляторов Delphi. Чтобы AL-IV его нашёл, поместите в целевую папку файл dcc32.cmd следующего содержания:
      "путь к dcc32.exe" "%1"
      (И затем скопируйте этот же файл в подпапку $TEST - чтобы можно было компилировать и тесты).
      Либо пропишите путь к директории, где живёт нужный файл dcc32.exe, в системной переменной среды PATH, и тогда содержимое файла dcc32.cmd:
      dcc32.exe "%1"
    • Для запуска компилятора javac необходимо иметь установленный jdk (версии 6, 7, 8), и путь к папке bin должен быть прописан в PATH. Так же, необходимо добавить ещё одну переменную среды JAVABIN, в которой прописать этот путь ещё раз - для компилятора AL-IV.
  • Если вы добавите ключ /run, то успешно собранная программа еще и запустится сразу после компиляции соответствующим компилятором. Есть возможность так же передать запущенному приложению параметры используя ключ /param [параметры в квадратных скобках].
 

П.С. В ПРИЛОЖЕНИИ (в конце этого описания) приводится подробный разбор настроек командного и конфигурационного файлов для компиляции конкретного примера.

 

Если не хватает библиотечных функций ...

  • В некоторых случаях это не проблема - если таких функций немного, и вы знаете, как обратиться к таким функциям на том целевом языке, который был выбран для компиляции кода из из AL-IV. Вам помогут так называемые "нативные" функции.
    Несколько советов:
  • Выносите все нативные функции в отдельный класс (или в несколько таких классов). Класс пометьте как NATIVE (модификатор в заголовке класса):
    CLASS {My_wrappers|_to_native_functions}, NATIVE, UNTESTED : ...
  • Отметьте как нативную функцию, которую вы вызываете, и в качестве тела функции поместите строковую константу:
    FUN Native_wrapper_name(param1, param2,
        param3) ==> TYPE, NATIVE, STATIC :
        "    return Some_native_function_call(...);" .

  • Если нативная функция должна содержать более одной строки кода, используйте префиксный символ @ перед первой строкой, чтобы автоматически добавить символы конца строки после каждой строки длинной константы:
    FUN Native..., NATIVE:
       @"    if (X_Param1 < 0) return -1;"
        "    ..."
        "    more code;" .

  • Если кроме добавления вашего кода внутри строк в тело нативных функций требуется добавить немного "своего" кода между функциями, используйте директиву
    NATIVE "текст" .
    размещённую между функциями.
    Учтите, что самые первые такие директивы, обычно начинающиеся соответствующим специальным ключевым словом, помещаются в специальные точки кода как содержимое операторов импортирования. Например:
    NATIVE "using System.Drawing.Imaging;" .
  • Если весь нативный текст разместить внутри кавычек недостаточно, используйте нативную функцию как переходник на истинную функцию целевой платформы, которую вы напишете уже без ограничений на директивы NATIVE. Сама функция может находиться при соблюдении некоторых условий рядом с нативным вызовом её же, в том же файле на целевом языке программирования:
    • файл должен иметь расширение, которое считается исходным для соответствующего целевого языка (pas - для Delphi, java - для Java, cs - для c#);
    • код AL-IV должен размещаться внутри C-комментариев
      /* ... */ (символы начала и конца комментариев должны размещаться в отдельных строках);
    • если дуальный язык программирования использует другие символы для начала и завершения многострочных комментариев, то код AL-IV по-прежнему размещается между символами /* и */, и дополнительно, вместе с этими символами заключается в комментарии этого языка. Например, для Pascal:
      (*
      /*
      .... код AL-IV
      */
      *)

      Или для Python:
      """
      /*
      .... код AL-IV
      */
      """
  • Учтите, что для компилятора целевого языка все файлы проекта, как сгенерированные компилятором AL4, так и добавленные напрямую (нативными функциями), должны быть скопированы в папку проекта. Поэтому для используемых нативными функциями файлов, в файл конфигурации опций компилятора, следует добавить (пока что вручную) команды:
    /copy путь\файл.ext
    (Файл копируется, но все комментарии, начинающиеся символами // в начале строки, замещаются предупреждением о том, что это только копия файла).
    Или, что лучше, следует добавить в исходный файл, использующий этот файл с нативными функциями, директиву
    NATIVE "///COPY имя_файла" .
 

Отладка кода

  • На данный момент, и в обозримом будущем, пошаговая отладка не будет доступна, и не планируется. Вместо этого у нас есть:

     

    • неубиваемое (хм, почти) приложение, которое не падает по каким-то глупым причинам, вроде выхода за границы массива, или нулевой ссылки на объект, или слишком глубокой рекурсии.
    • почти всегда можно добавить в код вызов функции, которая при определённых условиях что-то выведет полезное в консоль, в файл или на экран, и выведенное значение подскажет вам, где может быть проблема.
      (Лучше использовать блоки DEBUG: ... ; - их легко позже найти в коде и удалить или закомментарить, или отключить, добавив ключ /final в опции компиляции).
    • Начиная с версии 0.92.9, при компиляции кода в Delphi/VCL, есть возможность использовать инкрементальную компиляцию, когда после компиляции и запуска приложения на отладку, компилятор подхватывает модифицированные классы, перекомпилирует их в DLL, и полученный код (по запросу из вашей программы) подгружается на лету, без остановки приложения. Разумеется, есть ограничения:

       

      • нельзя изменять декларации методов, функций, полей класса;
      • нельзя добавлять новые или удалять существующие методы / функции / поля;
      • можно изменять только тело функций и методов;
      • функции, которые отрабатывают только один раз (например, CONSTRUCT), и уже были выполнены, повторно не вызываются, если это не предусмотрено вашим кодом;
    • Начиная с версии 0.94.7, ключ /$INCREMENTAL поддерживается для компиляции в C# (но без динамической дозагрузки кода в уже загруженное приложение: следует закрыть запущенное приложение, чтобы была выполнена перекомпиляция изменившихся классов и пересборка+запуск приложения);
    • Существует (с версии 0.91.1) возможность устанавливать ловушки (модификатор TRAP) на события обращения к полю класса, а так же получать доступ к стеку функций и к их счетчикам использования (при включенном режиме отладки /debug). Это чрезвычайно полезный механизм отладки: вы устанавливаете ловушку на запись значения в поле, анализируете в коде текущее и предыдущее состояние и при определенных условиях выводите в консоль важную информацию, например, весь стек вызовов. Далее вы устанавливаете, в какой именно функции и на каком именно по счету ее вызове происходят проблемы, и на следующей итерации выводите для этого вызова дополнительную информацию. Или анализируете код, приводящий к проблеме, и сразу обнаруживаете причину неверной работы кода. Метод ловушек позволяет существенно сократить число итераций и выводимой в консоль / лог информации для анализа при поиске возможных проблем.
    • в крайнем случае... - у вас есть код, который сгенерировал компилятор из AL-IV, и вы можете воспользоваться возможностями, предоставляемыми целевым языком и его инструментарием. Кстати, секционные комментарии вида
      ---------------- 'текст'
      копируются (почти всегда) в результирующий код на целевом языке - и по ним очень удобно отыскивать окрестности того кода, который может представлять интерес.

ЧАСТЬ 2. AL-IV:   Создание программ с графическим пользовательским интерфейсом

 

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

 

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

 

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

 

К сожалению, при таком подходе, помимо преимуществ, появляются и недостатки:

  • приходится учитывать наличие на всех поддерживаемых целевых платформах необходимых для работы компонент. На данный момент, поддерживаются 4 платформы для программирования ГПИ (Delphi-VCL, Delphi-KOL, Delphi BDS 10.2+ с библиотекой Firemonkey, C#-Windows Forms и Free Pascal-LCL).
     
  • приходится использовать такую парадигму разработки визуальных форм и диалогов, которая устраняет программиста из процедуры тщательной настройки взаимного расположения элементов на форме, вплоть до пикселя.

 

2.1. Дерево визуальных и невизуальных компонентов для разработки

 

 
 

Все стандартные визуальные управляющие элементы являются прямыми наследниками класса {Control}. Ниже идёт их краткое описание, в сравнении с функциональностью их аналогов из целевых платформ, на которых они, чаще всего, и реализованы.
 

AL-IV

C#

Delphi / FPC

Java (Android)

{Label} Label TLabel Label
{Button} Button TButton Button
{Checkbox} CheckBox TCheckBox CheckBox
{Combo},

не позволяет редактировать текст, только выбор значения

ComboBox TComboBox Spinner
{Edit} TextBox (Multiline = FALSE) TEdit TextView (Read only)/ EditText
{Memo} TextBox (Multiline = true) TMemo extView (Read only)/ EditText
{Listbox} ListBox TListBox ListView
{Progress} ProgressBar TProgressBar ProgressBar
{Paintbox} PictureBox TPaintBox View
{Date_picker} DatePicker TDateTimePicker TextView

 

 

Особенности визуальных управляющих элементов часто следуют из возможности реализации их функциональности через соответствующие "зеркальные" компоненты целевых платформ. Ограничения на функциональность элемента зачатую появляются вследствие того, что зеркальный компонент на одной из платформ содержит такое ограничение. Проще сразу ограничить функциональность соответствующего элемента в библиотеке для AL-IV, нежели пытаться преодолеть такое ограничение на конкретной платформе. И это всё-таки лучше, чем допустить существенно различное поведение элемента в зависимости от платформы, на которой исполняется приложение.
 

В правых колонках, соответствующих целевым платформам, при наличии особенностей реализации, имеются комментарии.
 

Например, для {Combo}: данный элемент не допускает прямой ввод значения, вследствие необходимости использования на платформе Java компонента с соответствующим ограничением. В случае необходимости выбора значения, отсутствующего в списке, либо список должен содержать дополнительный элемент (он может называться "ввод нового значения", или "...другое" или ещё как-то, и находиться в начале или в конце списка), либо задача реализуется другим способом - через кнопку или всплывающее меню, или просто вводом значения в соседнее текстовое поле. Т.е., большой проблемой данное ограничение не является, в то же время существенно упрощая разработку самого компонента {Combo}. Комбинированного в нём при этом остаётся выпадающий список в комбинации с полем отображения выбранного элемента.

 

Невизуальные управляющие элементы ({Dialog_file}, {Timer}, {Menu} и т.д.) - так же произведены от класса {Control}. Разумеется, для них свойства, относящиеся к внешнему виду, местоположению на форме, скорее всего, будут проигнорированы. От {Control} для них важно было унаследовать принадлежность родительской форме, и способ взаимодействия с соответствующим зеркалом элемента в нативном коде платформы.

 

2.2. Компоновка формы. Колонки.

 

Компоновка формы формально двухуровневая [см. дополнение в следующем пункте]: на плоскости формы размещаются колонки, внутри которых располагаются визуальные элементы (кнопки, метки, поля ввода, выбора и т.д.).

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

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

 

 

Более того, сами колонки не имеют соответствующего класса или объекта, доступного для управления, и управление колонками осуществляется через методы формы. Собственно, какое-либо особо сложное управление для колонок и не требуется: выравнивание колонки задаётся только в момент её создания.

Важно помнить, что в некоторых целевых системах фактическое расположение колонок может отличаться от предполагавшегося при разработке формы. Например, на ограниченном размерами экране смартфона, одномоментно могут быть не видны сразу все колонки, а выровненные 'TOP' и 'BOTTOM' могут отображаться по очереди, а для переключения между ними может использоваться перелистывание (например, жест "смахивания" с экрана или над экраном).

 

 

Если в конструкторе формы начать создавать визуальные элементы, не создавая колонку, то автоматически создаётся первая безымянная колонка, с выравниванием 'CLIENT' (т.е. занимающая всё пространство формы, если нет других колонок).

Если создавать несколько колонок с выравниванием 'CLIENT', то отображаться будет единовременно только одна - первая, для которой в событии формы column_hidden было возвращено FALSE.

 

Дополнительно, допускается создание "вложенных" перпендикулярных колонок с выравниванием 'LEFT'/'TOP', 'RIGHT'/'BOTTOM'. При создании для таких колонок должна указываться текстовая метка "родительской" колонки, выравнивание которой не должно быть параллельно выравниванию вложенной (т.е. если вложенная колонка имеет выравнивание 'LEFT'/'RIGHT', то "родительская" не может быть выровнена ни 'LEFT', ни 'RIGHT').

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

Следует учесть, что на некоторых платформах вложенные колонки таковыми не становятся, и отображаются как обычные колонки с соответствующим выравниванием (Android).

 

При автоматическом размещении элементов:

 

Для колонок, выровненных влево, вправо или по клиенту, реализуется автоматическое размещение визуальных элементов сверху вниз по умолчанию (имеется возможность указать явно выстраивание контролов в колонке сверху вниз и для горизонтальных колонок). При этом горизонтальные размеры элементов рассчитываются автоматически, так, чтобы либо элемент целиком занял один ряд, либо он был размещён в ряду вместе с его меткой, если позволяют размеры метки. (А если сразу за элементом создается {Paint_turtle}, то он так же занимает место в том же ряду, справа от предыдущего контрола).

 


 

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

 

Только одному элементу в колонке разрешается автоматическое изменение высоты вместе с изменением высоты колонки. И не все классы визуальных элементов могут автоматически изменять свою высоту. Это свойство относится только к {Memo}, {Listview} и {Paintbox}. Для того, чтобы задать автоматическое расширение такого элемента вниз, следует для него выполнить вызов:
Set_anchor_bottom(TRUE)

 

Для колонок, выровненных вверх ('TOP') и вниз ('BOTTOM'), обычно действует другое правило размещения элементов: слева направо (или справа налево, в некоторых языковых средах) с небольшим отступом между ними. Вертикальный размер для {Memo}, {Listview} и {Paintbox} может быть выставлен вручную, и вертикальный размер колонки, выровненной вверх или вниз подбирается по размеру содержимого.

Пример колонки с выравниванием вверх/вниз (схема):

 

 

Для таких горизонтальных колонок может задаваться так же свойство размещения контролов методом Set_controls_layout({controls_layout}) или в дизайнере формы. Возможные варианты:

'CONTROLS_LEFT' - все визуальные элементы размещаются слева направо. Если последний элемент класса {Edit}, {Combo}, {Paintbox} (и его наследники) имеет флажок "Расширение вправо/вниз", то он занимает остаток ширины колонки;

'CONTROLS_RIGHT' - все элементы прижаты к правому краю;

'CONTROLS_CENTER' - Элементы равномерно распределены, с одинаковыми расстояниями между ними и краями колонки (если есть место, иначе как для 'CONTROLS_LEFT');

'CONTROLS_JUSTIFY' - аналогично предыдущему, но левый и правый элемент прижаты к краям колонки;

'CONTROLS_LEFT_LAST_RIGHT' - аналогично 'CONTROLS_LEFT', но последний элемент прижимается к правому краю (если есть место);

'CONTROLS_TOP_TO_BOTTOM' - для горизонтальной колонки указывается, что контролы будут размещаться как для вертикальной, сверху вниз. Вероятно, при этом следует задать колонке увеличенную высоту, чтобы элементы в этой колонке были видимы;

'CONTROLS_VERTICAL_2|_COLUMNS' - работает и для вертикальных, и для горизонтальных колонок, элементы размещаются в 2 колонки, занимая сначала левую половину колонки, затем, начиная с контрола с индексом N/2 (где N= число контролов в колонке), правую половину.

Существует так же возможность для любых типов колонок отказаться от автоматического размещения элементов в колонках вызовом
Set_column_auto_arrange(FALSE), и выполнить размещение самостоятельно. Например, в событии формы resize. Но на некоторых платформах такой вызов может быть проигнорирован, это так же следует учитывать.

 

2.3. Обработка событий

 

В AL-IV нет указателей на функции. Делегаты, как в C#, или "слушатели" (listeners), как в Java - это слишком громоздкий способ обрабатывать события. В AL-IV - единственная возможность обработать события визуальных элементов формы, это переопределить в своей форме соответствующие методы формы, например, click, key_press, mouse_move, timer и т.д.

Для случаев наследования контрольных элементов, некоторые события вызываются в самих контрольных элементах (например, движения мыши).

 

Как и все методы, начинающиеся со строчной буквы, эти методы являются защищёнными. Они так же помечены маркером CALLBACK, т.е. не предназначены для вызова самим кодом пользователя. (Это ограничение не наследуется в производном классе, защищая только сам прототип метода от неправильного использования).

 

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

 

Рекомендуется сколько-нибудь сложную обработку выносить в отдельные методы, оставляя в основном обработчике только действия, не требующие больше пары-другой строк кода.

 

В случае, если есть необходимость свести в одно место обработку одного события от нескольких источников (кнопок, меню, клавиатуры), можно использовать для этого обработчик событий меню, вызывая его из всех альтернативных методов. (Чтобы компилятор не возмущался по поводу неправомерного использования CALLBACK-метода menu, следует выделить код в свой метод, например, operation, и вызывать его из обработчиков menu, click и других, передавая необходимый параметр).

 

Можно значительно упростить разработку, если вместо классов {Form} и {Dialog} для прототипирования своих форм и диалогов использовать классы {Form_common} и {Dialog_common}, соответственно. Эти классы форм берут на себя ряд типовых видов работ, таких, как, например, обслуживание событий клавиатуры и мыши для таблиц и деревьев ({Paint_lines}, {Paint_tree}), в том числе прокрутку колесом мыши. Упрощают поддержку вывода подсказок, позволяют задать единые стили оформления (цвет) для всех форм проекта, для всех используемых таблиц ({Paint_table}), автоматизируют обработчики кнопок по умолчанию/отмены. При этом они так же легко расширяются дополнительным функционалом.

 

2.4. Запрещение / скрытие визуальных элементов

 

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

 

Метод disabled вызывается только для элементов, предварительно добавленных в список grayable[]. Аналогично, метод hidden - только для элементов, добавленных в список can_hide[]. Добавление элементов лучше в эти списки лучше всего выполнить один раз в конструкторе формы. (При визуальной разработке, в дизайнере такое добавление выполняется установкой соответствующего флажка в области свойств контрола, "Может быть недоступен/скрыт").

 

Управление видимостью колонок так же выполняется в обработчике column_hidden. Отличия в том, что в качестве параметра передаётся текстовое имя колонки, и метод вызывается для каждой колонки - предварительное указание тех колонок, для которых возможно скрытие, не требуется.

 

2.5. Всплывающее меню

 

В AL-IV предлагается использовать только всплывающее меню. Для имитации главного меню возможно использовать колонку с кнопками, выровненную по верхнему краю формы ('TOP'), в которой нажатия на кнопки вызывают отображение на экране соответствующих всплывающих меню.

 

Меню создаётся на основе набора строк, разделённых символами конца строки #NL. Вы можете заготовить такую строку как константу, или сформировать её в коде непосредственно в точке вызова меню (или в отдельной функции - на усмотрение разработчика).

 

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

Дополнительные атрибуты пунктов меню, если они есть, записываются через запятую после синонима пункта меню (до двоеточия). На данный момент возможны два дополнительных атрибута - disabled и checked.

Например, вызов традиционного файлового меню для кнопки Файл (в "главном меню" из кнопок):

 popup_menu(@
    "OPEN:Open"
    "SAVE:Save"
    "SVAS:Save as..."
    "-"
    "PRNT,disabled:Print"
    "PRVW,disabled:Print preview"
    "-"
    "EXIT:Exit")

 

Строка, формирующая меню, передаётся функции popup_menu, что приводит к отображению всплывающего меню. В этой точке выполнение текущего обработчика должно заканчиваться. Управление в программу вернётся вместе с вызовом CALLBACK-метода формы menu_item, когда пользователь выберет один из пунктов меню и "нажмёт" его (если нажмёт клавишей на клавиатуре или кликнет мышью). Точка отображения всплывающего меню зависит от того, обработчик какого мышиного события был последним вызван. В случае обработчика click это - левый нижний угол элемента, по которому произошёл клик (неважно, мышью или другим способом, например - с клавиатуры).

 

В обработчике событий меню следует проанализировать имя сработавшего пункта меню (используя CASE sender_alias ? ...), и выполнить соответствующие действия.

 

 

Для удобства использования визуального редактора меню (входит в состав визуального Дизайнера формы), для формирования меню предлагается использовать ряд функций класса {Menu|_create}. Приведенный выше код меню с использованием этих функций будет выглядеть, например, так:

 popup_menu(
    "" Item(  "OPEN",
              "&Open" )

    "" Item(  "SAVE",
              "&Save" )

    "" Item(  "SVAS",
              "Save &as..." )

    "" Separator

    "" Item(  "PRNT",
              "&Print"
       ).Disabled(!can_print)

    "" Item(  "PRVW",
              "Print pre&view"
       ).Disabled(!can_print)

    "" Separator

    "" Item(  "EXIT",
              "&Exit"  ) )

 

 

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

 

2.6. Рисование в канве

 

На форме (в одной из колонок, как обычно) могут размещаться визуальные элементы, предназначенные для рисования. Рисование выполняется в событии-методе paint формы, используя объект Canvas класса {Canvas} данного контрольного элемента. На самом деле, рисование выполняется (обычно) на буферном битмапе ({Bitmap} - класс для хранения и обработки растрового изображения), и результат копируется на экран по окончании работы обработчика. Это уменьшает количество мельканий в процессе перерисовки формы.

 

Аналогичным образом, рисование может быть выполнено на любом объекте {Bitmap}, так же через методы его объекта Canvas класса {Canvas}.

 

Следует учесть, что все координаты при работе с визуальными элементами в AL-IV, задаются не в пикселях, а в поинтах. Это обеспечивает независимость от разрешения экрана, и привязку к текущему выбранному масштабу отображения.

 

На канве по умолчанию так же используются поинты, но используя открытое поле Units, имеется возможность указать и другие единицы измерения, например, пиксели.

 

Канва содержит ряд методов, позволяющих выполнить рисование графических примитивов, используя текущие цвета и стили шрифта, пера и кисти. Например, Erase, Rect, Line, Ellipse, Arc, Text, Poly. Кроме того, имеется возможность выполнять аффинные преобразование системы координат, выполняя масштабирование (Scale), Смещение (Offset) и повороты (Rotate). Функция Reset_transform сбрасывает все установленные преобразования.

 

Следует учитывать, что рисование в канве элемента {Paintbox} (до вызова метода paint) начинается с того, что все трансформации сбрасываются (как если бы до этого не делалось никаких трансформаций).

Так же, может показаться непривычным то, что для класса {Paintbox} свойство Canvas вне метода paint (до его вызова, и после его вызова) недоступно: возвращается NONE-объект, любые действия с которым ни к чему не приводят. Это означает только одно: рисовать в элементе {Paintbox} можно только, когда система решит, что требуется его перерисовка, и только во время вызова метода paint. Например, когда элемент изменил размер, или на экране пропало или было перемещено накрывающее его сверху окно. Можно попросить систему перерисовать элемент, вызвав его метод Invalidate_all, но при этом не гарантируется немедленный вызов метода paint - может пройти некоторое время.

 

Класс {Paintbox} позволяет определить содержимое большего размера, чем видимая область, и задать возможность прокрутки содержимого. Видимость вертикальной/горизонтальной линеек прокрутки определяется только при создании {Paintbox}-контрола. На основе {Paintbox} созданы контролы {Paint_tabs},  {Paint_lines} (и его наследники {Paint_table} и {Paint_tree}), и {Paint_turtle} .

 

2.7. 3D визуализация (Open GL)

 

Класс {OpenGL} может использоваться для обращения к функциям Open GL автомата в стиле, максимально близком к классическому. При этом значения константных параметров контролируются на этапе компиляции. Например, при вызове функции glEnable можно передать только одну из констант, разрешенных в качестве параметра для этой функции (например, GL_BLEND, GL_LIGHTn, GL_TEXTURE_2D и т.д.) Но при попытке передать что-то неподходящее компилятор выдаст ошибку.

Для работы на мобильных платформах используется модификация Open GL ES (Android), в которой некоторые базовые функции не поддерживаются. Однако, класс {OpenGL} поддерживает работу функций glCallList/glCallLists/glNewList и т.п., а так же gluNewQuadric/gluSphere/... - в режиме симуляции. Так что, любимые примеры из вводных учебников по Open GL будут работать как обычно.

 

Пример работы с классом {OpenGL} имеется в приложении Test_visual_projects\Test_OpenGL.

 

2.9. Обслуживание длинных операций

 

В отличие от большинства языков программирования, AL-IV прикладывает особые усилия для предотвращения возможности бесконечного зацикливания (а так же, неограниченной рекурсии). В частности, в языке AL-IV есть только один оператор для организации бесконечного цикла FOR INFINITE, и его использование штрафуется (необходимо указывать спецификатор INFINITE для класса, в котором используются такие операторы).

Но это не все. Достаточно длинный цикл может возникнуть в результате нескольких вложенных циклов, например. Поэтому, для каждого цикла FOR, независимо от того, что в нем делается, в его теле на каждой итерации увеличивается специальный глобальный счетчик активности. Каждый раз, когда этот счетчик достигает значения 65536, вызывается системная функция check_long_operations. Эта функция сбрасывает глобальный счетчик, и анализирует наличие присоединенных обработчиков.

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

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

Для того, чтобы обеспечить движение линейки прогресса в этом диалоге, а так же отобразить необходимый текст, кратко разъясняющий суть выполняемой работы, и стадию выполнения, достаточно подключить в импорте класс {Long_operation}, и воспользоваться свойством формы Long_operation (этого класса). Его методы Set_description, Set_stage, Set_progress обеспечивают пользователя необходимой информацией, и при этом форма длительной операции ведет себя все так же - показывается только спустя 3 секунды, и исчезает по окончании операции автоматически. И так же позволяет перевести приложение в режим паузы или остановить, при необходимости.

 

Разумеется, данную функциональность, если она не используется или по каким-то причинам крайне нежелательно, можно полностью отключить, добавив в опции компилятора команду /$NOLONGOP.

 

Пример использования {Long_operation} имеется в демо-приложении "100", в котором используются очень активные вычисления для поиска комбинаций операций между заданными цифрами, приводящих к выражению, результатом вычисления которого будет заданное число (100 по умолчанию).

 

ЧАСТЬ 3. Среда разработки: редактор IDE AL4

Компиляция редактора IDE AL4

 

Архив IDE_AL4.zip распакуйте так, чтобы папка IDE_AL4 оказалась вложенной в корневую папку AL-IV.

В Windows (XP, 7, 8.x, 10): откройте папку IDE_AL4 и выполните командный файл _compile-C#.cmd. Если установлен требует фреймворк .Net, проект будет скомпилирован, и в папке IDE_AL4\Compiled появится исполнимый файл IDE_AL4.exe.

Если по какой-либо причине не удаётся обеспечить наличие требуемой версии .Net, попробуйте установить Delphi 7 (32-битную версию), настроить ее в соответствии с инструкциями, и откомпилировать редактор IDE_AL4 командой _compile_Delphi.cmd. Результирующий бинарный файл будет находиться в папке Compiled_Delphi.

Аналогично, для прочих возможных целевых компиляторов (Java, C++, Python...) Хотя использование IDE откомпилированной для других версий, нежели C# и Delphi (KOL/VCL) может быть затруднено из-за медленной скорости отрисовки графики / медленной обработки строк в этих целевых системах.

 

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

 

Имеется возможность откомпилировать IDE для ОС Linux, в том числе непосредственно из Linux (в настоящее время - через Lazarus+Free Pascal). Воспользуйтесь инструкциями по настройке компилятора Lazarus для работы в Windows и Linux, после чего вызовите соответствующие командные файлы для сборки приложения IDE AL4 (_compile.sh, _compile_final.sh).

 

Начиная с версии 0.92.7, в IDE был добавлен визуальный дизайнер формы.

 

Русификация (другая локализация) редактора IDE AL4

 

Для обеспечения переключения на предпочитаемый язык интерфейса, скопируйте языковые файлы (с расширением .lng) в ту же папку, что и исполнимый файл редактора. После чего, после запуска приложения, в пункте меню Вид \ Выбрать язык (Select language) становится возможным выбрать соответствующий язык из списка.

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

 

Особенности отображения кода в IDE_AL4

 

Заголовки функций, методов, классов, и других деклараций уровня класса отображаются увеличенным вдвое шрифтом. Для того, чтобы этот способ отображения работал, необходимо соблюдение ряда требований (кроме включения соответствующего режима в меню "Вид"), а именно:

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

Цветные линии между начальной и последней строкой блока кода показывают уровень вложенности блока и его завершенность. Линии отображаются с правой стороны от текста, не затрагивая отступы слева.

Цвет линий (и операторов) для вложенных операторов CASE / FOR всегда имеет одинаковый порядок (в светлой цветовой схеме: СВЕТЛО-ЗЕЛЕНЫЙ, СИНИЙ, КОРИЧНЕВЫЙ, ОЛИВКОВЫЙ). Цвет и стиль изображения для вложенных операторов PUSH / DEBUG другие и не смешиваются с линиями операторов CASE / FOR. Всегда легко определить при написании кода просто по цвету, что число уровней вложенности начинает превышать  допустимые три уровня (+ четвертый, на котором допускается разместить только один оператор каждый раз).

Отсутствие линий от начала блока к его окончанию на момент редактирования кода показывает наличие каких-то проблем в оформлении блока (недостающие или избыточные символы ';'). Для того, чтобы линии отображались для блока, необходимо так же соблюдение дополнительных условий:

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

 

Специфические операции по редактированию текста

 
  • Нажатием CTRL+/ комментируется / раскомментируется блок кода добавлением / удалением символов начала комментария // в начале каждой строки блока. Действует на блоки кода внутри функции. Основное назначение - быстрое комментирование / раскомментирование блочных операторов DEBUG (вместе с вложенными блочными операторами). DEBUG-блоки удобно не удалять из кода, а комментировать в случае, если они могут понадобиться в будущем.
  • Поиск по образцу (CTRL-F / F3(вперед) / F2(назад)) имеет дополнительные опции: "без учета пробелов", "игнорировать комментарии", что позволяет (например) быстро обнаружить еще не закомментированные операторы DEBUG, и другие.
  • Операция "вставить недавнее" (Ctrl+Shift+V) упрощает множественные изменения в коде, когда необходимо вставлять несколько различных образцов (например, в начале и в конце блока). Или, с этой операцией возможно скопировать в буфер обмена несколько различных фрагментов в различных частях кода, после чего вставить их в несколько других мест в тексте, не возвращаясь неоднократно назад / вперед в поисках мест для повторного копирования.
  • Операция CTRL+' позволяет быстро снять начальную и конечную кавычку для блока кода, каждая строка которого представляет собой строковую константу в кавычках. Или, наоборот, заключить каждую строку выделенного блока строк в двойные кавычки. Эта операция может быть полезна при преобразовании нативного кода для использования его либо непосредственно в чужеродном коде, либо в теле нативной функции, когда нативный код передается компилятору в виде многострочной строковой константы.
  • После небольших изменений в текущей строке, в нижней части окна с кодом выводится подсказка xxxx ==> yyyy. Если в этот момент нажать Ctrl+R, то открывается диалог замены с установленными значениями что искать = xxxx, на что заменить = yyyy. Что может упростить массовую замену (например, одного идентификатора - на другой, в том числе - только в текущей функции).

Навигация и подсказки по функциям, методам и пр.

  • Переходы к определениям символов (CTRL-ENTER), определенных в том же классе, доступны всегда, даже без загрузки проекта. Навигация назад (CTRL-<) и вперед (CTRL->) так же доступны всегда.
  • Существует возможность получать подсказки для незагруженных классов: для этого надо построить индекс классов (меню Файл - Индекс классов). При этом предлагается выбрать корневую директорию папки, в которой лежат индексируемые классы. Например, для индексирования всея библиотеки, выбирается AL4\Library.
    Точно так же можно проиндексировать и классы своего личного проекта.
  • Индентация в коде пробелом и табуляцией и Shift+проблом и Shift+табуляцией.
    Для иcправления индентации на одну табуляцию следует выделить код и нажать TAB (или Shift+TAB - для уменьшения уровня индентации). Для индентации по одной позиции вправо/влево используются ПРОБЕЛ и Shift+ПРОБЕЛ. Для строк кода (обычно нативного), заключенного в "кавычки" или ''двойные апострофы'', индентация с пробелом работает без сдвигания (по возможности) самих кавычек.

 

Отладка со встроенным отладчиком


 

  • Встроенный отладчик работает только для проектов Delphi (VCL/KOL) и FPC (но запуск приложений и просмотр сообщений компилятора работает и для проектов C#);
  • Сначала требуется "открыть проект" командой File | Open project (Файл | Открыть проект). Проект - это командный файл, используемый для запуска компиляции (и запуска приложения, если указан ключ /run);
  • После этого становятся доступны команды
    F8 - компиляция приложения (если уже откомпилировано, выполняется команда отладчика "Шаг с обходом" (Step over);
    Shift-F8 - компиляция приложения и запуск с отладкой (только Delphi/FPC);
    Ctrl-F8 - компиляция и запуск без отладки;
    Ctrl-Shift-F8 - компиляция без запуска;
 

В отличие от отладчиков, управляющих работой отлаживаемой программы как процессом, с полным доступом к ее памяти, отладчик IDE AL4, на деле лишь "общается" с кодом отлаживаемой программы через два файла в директории с программой:

breakpoints.txt - здесь IDE размещает точки останова;
stopped.txt - здесь отлаживаемая программа выводит информацию о текущей остановке, включая номер функции, номер строки в функции, позицию в строке, стек функций, а так же значения локальных переменных и полей объекта THIS (если это метод).

 

Для того, чтобы отладка была возможна, компилятор размещает в финальном коде перед каждой строкой кода конструкцию
if _stopped_(функция, строка) then _out_('функция строка:позиция', _vars_); Так же, в каждой функции или процедуре формируется вложенная функция _vars_, которая формирует строку, содержащую значения локальных переменных и полей - которые будут при остановке выполнения сохранены в файле stopped.txt, и затем отображены отладчиком IDE.

Разумеется, это несколько замедляет выполнение отлаживаемой программы, но не в десятки раз, т.к. пока не выполнены условия остановки, функция _out_ не вызывается (и _vars_, соответственно - тоже).

 

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

Но есть и некоторые полезные особенности. Например, отладка может быть запущена без точек остановки, и затем выполнение приостановлено в произвольном месте командой F7 в IDE. Если требуется применить изменения в коде, то достаточно закрыть программу и перекомпилировать/перезапустить ее (Shift-F8), и она остановится в той же точке останова, как будто продолжает выполняться. Так же, и IDE может быть перезапущен и присоединен к уже начавшейся пошаговой отладке (хотя, польза может быть разве что при отладке самого отладчика IDE).

 

Точками останова являются все букмарки в коде, как номерные (CTRL-Shift-цифра), так и неномерные (клик в колонке номеров строк или Ctrl-Shift-B - как обычно). Очевидно, что чем больше выставлено точек останова, тем медленнее будет работать отлаживаемая программа (но все равно не в десятки раз медленнее - если точек останова все еще меньше десяти).

Установка точки останова (букмарка) на первой строке функции эквивалентна установке точек останова на всех ее операторах.

 

Кнопки управления отладкой (Shift-F5, F6, Shift-F6, F7, Shift-F7, F8, F9) - могут быть нажаты как при активном окне отладчика, так и в главном окне IDE.

Shift-F5 - запуск без точек остановки. Выполнение все еще можно прервать (F7);

F6 - выполнение до возврата из текущей функции;

F7 - шаг со входом;

Shift-F7 - выполнение до текущей строки в редакторе IDE (фактически, устанавливается временно одна дополнительная точка останова - но выполнение может остановиться на любой ранее установленной точке останова);

F8 - шаг с обходом (фактически, выполнение до любого оператора в этой же функции или до выхода из функции);

F9 - выполнение до следующей точки останова. Может быть прервано по F7, как всегда.

 

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

 

ПРИЛОЖЕНИЕ 1. AL-IV: Магия командных файлов для запуска компилятора

Настройка запуска компилятора

 

Рассмотрим работу командных файлов на конкретном примере. В директории A4\Test_projects\_Hello_world находится файл _compile-C#.cmd. Его содержимое:

 

%AL4%\AL4\CSharp_build\AL4CSharpCompiler.exe /run /op - /@ %AL4%\AL4\Test_projects\_Hello_world\compile-C#.txt

pause
 

Первый путь в первой строке - это путь к компилятору. Он зависит от того, в какой целевой язык компилируется наш проект этим командным файлом. Для компиляции  в C# используется AL4CSharpCompiler.exe, для компиляции в Delphi-Pascal - AL4DelphiCompiler.exe, и т.д. (причем, каждый такой компилятор лежит в своей собственной папке).

Далее следуют ключи запуска. Самый важный из них /@ путь-к-конфигурационному-файлу.

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

 

Переходим к содержимому конфигурационного файла.

 

1

2
3
4

5
6
7

8
9

10
11

12

 

Hello_world.al4

/src %AL4%\AL4\Test_projects\_Hello_world
/src %AL4%\AL4\Library
/src %AL4%\AL4\Library\_CSharp

/ext cs
/ext2 al4
/v

/dst %AL4%\AL4\Test_projects\_Hello_world\Compiled
/prj Hello_world

/$REPORT_LEAKS=
/RUN

#/op -
 

Теперь по порядку.

 

1 - это имя входного файла. Следует указывать или полный путь (хотя бы содержащий переменные среды, либо полный путь, как в этом случае, должен быть добавлен ключом /src).

 

2, 3, 4 - ключ /src путь - задает список путей, по которым компилятор должен отыскивать импортируемые классы:

2 - путь к директории самого проекта. Должен быть указан обязательно, либо ключом /src, как в этом примере, либо при указании имени главного класса проекта.

3, 4 - пути к используемым библиотечным классам. Пути могут отличаться, в зависимости от целевого языка / фреймворка / операционной системы. Например, в этом примере:

4 - путь к нативным классам, предназначенным только для C#. В случае другого целевого языка это должен быть другой путь. Например, для Delphi/VCL этот путь должен быть замене на два:
%AL%\Library\_Delphi
%AL%\Library\_Delphi\VCL

 

5, 6 - ключи /ext, /ext2, /ext3 задают основное и дополнительные расширения для исходных файлов. Для AL-IV расширение по умолчанию (и после просмотра всех указанных явно расширений) используется .AL4, но для нативного класса удобно помещать код AL-IV внутрь исходного файла на целевом языке.

 

7 - ключ /v задает несколько более подробный вывод компилятора, чем обычно. Есть ещё самый подробный вариант /vv.

 

8 - ключ /dst путь - задает путь для размещения выходных файлов. Для компиляции тестов, к этому пути будет пристыковано имя поддиректории \TEST$. В случае успешного построения, результирующий исполнимый файл (или набор таких файлов будет находиться в указанной директории. Так же, как и сгенерированные компилятором исходные файлы на целевом языке.

 

9 - ключ /prj - задает имя проекта (обычно - имя исполнимого файла). Необязателен, если не задавать - обычно в качестве имени проекта назначается имя входного класса.

 

10 - ключ /$REPORT_LEAKS= - специфичный для компилятора (но поддерживается практически всеми версиями). Наличие такого ключа означает, что результирующая программа будет подсчитывать выделяемые и высвобождаемые объекты, и по окончании работы выведет в файл отчет о возможных утечках памяти. Ключ несовместим с некоторыми опциями (компилятор предупредит о проблемах при их наличии).

 

11 - ./RUN - ключ задает необходимость запуска откомпилированной программы.

 

12 - ключ /op nnnn - управляет оптимизацией кода. Вариант /op - - отключает все оптимизации. В данном примере строка с опцией /op начинается с символа #, т.е. закомментирована, и опция применяться не будет (код будет оптимизирован по умолчанию).

 

Существуют и другие ключи, при этом ключи вида /$LLLLLLLLL зависят от конкретной версии компилятора. Список основных ключей может быть получен при запуске компилятора в командном терминале без параметров.

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

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

 

ПРИЛОЖЕНИЕ 2. Постепенный переход на AL-IV в существующем проекте

(в процессе)

Постановка задачи по миграции кода в AL-IV

 

Предположим, у нас имеется некое приложение, разработанное на Delphi + VCL или Delphi + KOL, с большим количеством форм, и привязанного к ним кода. И по каким-то причинам нам, к примеру, желательно перейти к AL-IV (например, предполагается возможность запуска на платформе Linux, или требуется уйти от неподдерживаемой версии компилятора Delphi, или по другим причинам). Но перевести в AL-IV сразу все 10 или больше форм приложения не представляется возможным. Поступаем следующим образом.

 

Решение: изменить синтаксис AL-IV - программ на Pascal-подобный

 

Начиная с версии 1.3.0, в AL-IV имеется поддержка синтаксиса Pascal. А именно, компилятор воспринимает классы, написанные как бы на языке Pascal (несколько урезанном). Для этого в начале класса размещается 5 строк:
(*
/*
    [SYNTAX="PASCAL"]
*/
*)

 

После чего размещается код на языке Pascal, начиная с директивы unit, имени модуля - как обычно в Паскале - и заканчивая директивой end с точкой. Более того, не запрещено просто добавить вышеозначенный комментарий с указанием синтаксиса "PASCAL" в уже существующий модуль и попробовать подать его на вход AL-IV-компилятора.

 

Неподдерживаемые конструкции

 

В большинстве случаев с первой попытки ничего не выйдет, так как AL-IV воспринимает далеко не все конструкции Delphi/Free Pascal, и даже не все конструкции стандартного языка Pascal. Например, не поддерживаются:

 

- оператор do ... while;

- оператор with ... do;

- массивы массивов;

- переопределение типов данных на основе других типов
type x = y;

- глобальные переменные;

- параметры конструкторов (игнорируются с выдачей предупреждения);

- определение дополнительных классов с методами (или унаследованных от других классов), кроме единственного класса в модуле [т.к. в AL-IV модуль - это и есть класс, и дополнительные структуры не могут быть полноценными классами];

- необязательные параметры и параметры со значениями по умолчанию;

- массивы, создаваемые "на лету" путем заключения в квадратные скобки списка произвольных выражений;

- индексы в константном массиве должны быть целыми числами начинаться с нуля (в Pascal - с произвольного целого числа, или вообще использоваться другой тип, например, перечисление или Boolean);

- нет свойств (property) с несколькими индексами;

 

Строгие правила AL-IV в коде Pascal

 

Так же, продолжают действовать некоторые строгие правила AL-IV по оформлению кода (хотя большая часть все-таки смягчена). А именно:

- длина строки кода, не считая комментариев, не должна превышать 80 символов;

- линейный блок кода не может содержать более 7 простых операторов и более 7 блочных операторов, либо блок должен быть разделен на части операторным комментарием (в синтаксисе Pascal он записывается в форме
{@-------------------------- 'label'}

- в AL-IV нет var-параметров, и все прочие параметры должны использоваться как константы (код, который не удовлетворяет этим требованиям, должен быть модифицирован);

- имена полей, функций, констант не должны быть менее 8 символов, или должны быть дополнены в форме:
Name{|extended_name}: type1;
function Foo{|_doing_something}(...): type2;

 

Смягченные правила AL-IV в коде Pascal

 

Для синтаксиса а-ля-Паскаль в язык введены смягчающие правила, позволяющие использовать особенности языка Pascal с минимальным числом переделок в коде:

- регистронезависимость имен функций, переменных, типов и т.д.

- снято ограничение на глубину вложенности операторов (if/case, for/while);

- разрешено не указывать квадратные скобки при использовании массивов как самостоятельных объектов (например, как параметров функций);

- не требуется указывать Clone/Dismiss при копировании структур (всегда используется "клонирование");

- разрешено присваивать значения полям и "методам", для которых определен SETTER (т.е., аналог присваивания значения свойствам);

 

 

 

Ручное преобразование кода Pascal в AL-IV: условная компиляция

 

Иногда возникает необходимость писать два варианта кода - для обычной компиляции с Delphi или Free Pascal, другой - для AL-IV. Причем, в случае AL-IV может понадобится возможность написать код именно на AL-IV, а не в виде Pascal-кода.

 

Для случая кода AL-IV, используется конструкция
(*$ifdef al4code*)
    ... пишем здесь код для AL-IV на языке AL-IV
    например,
    DEBUG: << "We are here"#NL ;
(*$else*)
    Код на языке Pascal для прежнего Паскаль-варианта
    (опционально)
(*$endif*)

 

Для случая особого варианта Pascal-кода (или когда код вообще не нужен в случае AL-IV):
(*$ifdef al4*)
    ... Пишем код на языке Pascal - он будет конвертироваться в AL-IV и компилироваться компилятором языка AL-IV
   ... Или не пишем код в случае, когда нужно просто закомментарить код Pascal в ветке else
(*$else*)
    ... Здесь остается вариант для прежнего Pascal-кода
(*$endif*)

 

Замечания:

  • Обязательно используются комментарии вида (*$ ... *) для оформления таких директив условной компиляции. Комментарии вида {$ ... } полностью игнорируются конвертером синтаксиса Паскаля, и могут использоваться в обычном коде в ветви (*$else*) этих комментариев;
  • Директивы (*$...*) могут записываться в любом регистре, но пробел между ifdef и al4 или al4code должен быть ровно один, и никаких пробелов между звездочками и текстом быть не должно;
  • Директивы (*$...*) записываются в отдельных строка кода;
  • Ветвь (*$else*) всегда может быть опущена.

 

Ручное преобразование кода Pascal в AL-IV: трансформация формы

 

Программирование в Delphi во многом перпендикулярно программированию в AL-IV (и не только в Delphi), и в случае визуального программирования ситуацию, на первый взгляд, еще хуже: нет ничего, кроме минимального набора контролов, нет возможности как попало размещать эти контролы на формы, иначе происходит обработка событий.

Но все (или многое) решаемо.

 

Во-первых, вам не понадобятся панели: колонки AL-IV не являются их прямой заменой. Поэтому все панели в декларации формы лучше всего скрыть от AL-IV компилятора директивами (*$ifdef al4*), поместив в часть (*$else*).

Далее, необходимо сформировать конструктор формы, если он еще не создан, и в нем в директиве (*$ifdef al4code*) прописать создание нужных контролов и колонок, используя синтаксис AL-IV.

Разумеется, для всех контролов необходимо найти ближайшие замены, а если таких нет, то придется переделать Delphi код так, чтобы использовать контролы, имеющие аналоги.

Например, в проекте ниже (Глазомер) использовалось 5 компонентов TShape на панели, чтобы пользователь кликом по ним делал выбор. Эта часть кода была переписана на использование TPaintbox, а список TShape успешно был заменен на массив прямоугольников TRect.

 

События в форме Delphi обычно пишутся для каждого контрола и для каждого вида события в отдельных процедурах-обработчиках, тогда как в AL-IV имеется один обработчик каждого вида - один на все контролы (после чего, разумеется, можно в зависимости от отправителя, перенаправить обработку на свою функцию). Соответственно, имеет смысл выделить блок кода, защищенный директивой (*$ifdef al4code*), и разместить в нем обработчики формы AL-IV, перенаправляющие обработку на соответствующие обработчики, написанные изначально на Pascal. Например:


(*$IFDEF AL4CODE*)
OVERRIDE paint :
  CASE sender_alias ? ["HOUSE"]: House.Canvas.Units = 'PIXELS'
                                 HousePaint(THIS)
                      ["TESTS"]: Tests.Canvas.Units = 'PIXELS'
                                 TestsPaint(THIS) ; .

OVERRIDE mouse_down :
  CASE sender_alias ? ["TESTS"]: TestsMouseDown(THIS, mouse_button, 0,
                            X= Tests.Form_X_points_to_Control_pixels(mouse.X),
                            Y= Tests.Form_Y_Points_to_Control_pixels(mouse.Y))
                      ; .

OVERRIDE mouse_double_click :
  CASE "kol" IN Platform_info.Lower ? mouse_down ; .

OVERRIDE click :
  CASE sender_alias ? ["MORE"]: ButtonMoreClick(THIS) ; .

OVERRIDE timer :
  CASE sender_alias ? ["ANIM_T"]: AnimationTimerTimer(THIS) ; .
(*$ENDIF*)

 

При наличии процедур рисования на канве следует учитывать, что в Delphi единицей измерения является пиксель, тогда как в AL-IV - обычно point, но может выполняться переключение и на другие единицы измерения, в том числе на пиксели. При рисовании на канве TPaintbox-контрола, код AL-IV автоматически переходит в "естественную" дл Delphi единицу измерения, но в случае рисования на других полотнах, отслеживайте эту ситуацию сами.

То же самое касается и событий мыши: Delphi-процедуры хотят работать с пикселями, а в AL-IV события мыши хранят координаты в point'ах, причем не относительно контрола, на котором произошло событие, а относительно всей формы. Поскольку работы с координатами мыши не является обычной в каждой форме Delphi (и требуется далеко не в каждом приложении Delphi), конверсию поинтов в пиксели вы тоже сделаете сами, вызвав соответствующие функции из модуля Delphi2AL4.pas.

 

Ручное преобразование кода Pascal в AL-IV: глобальные переменные

 

В AL-IV нет глобальных переменных, и конструкция var на уровне модуля языка Pascal вызывает ошибку конвертации. Чтобы работать с этими переменными в обоих вариантах - и в прежнем Delphi-проекте, следует переместить все глобальные переменные в главную форму. При этом сама главная форма должна быть доступна как в Delphi-проекте, так и в AL-IV - после трансформации.

Предположим, переменная главной формы называется fmMain. В этом случае в проекте Delphi все обращения к глобальным переменным превращаются в fmMain.SomeVar. В частности, если речь идет о глобальной переменной некоторой дочерней формы fmChild1, то обращение к ней должно перейти в fmMain.fmChild1.

Чтобы в контексте методов всех форм, кроме главной, идентификатор fmMain распознавался как ссылка на объект главной формы, и при этом не пришлось идти по длинному пути (* - см. ниже), лучше всего выполнить следующее:

В модуле главной формы прописать функцию, имя которой совпадает с именем главной формы (в нашем конкретном примере это fmMain). Это должна быть именно функция, а не метод (догадайтесь, почему). Чтобы не создавать для каждого возможного целевого фреймворка/языка программирования собственный вариант нативного модуля, который "добывает" ссылку на главную форму, прописываем в теле этой функции обращение к уже готовой функции Get_main_form, и приводим полученный результат к типу главной формы.

В случае AL-IV кода:
FUN fmMain|_form ==> {Fmmain} := Get_main_form.{Fmmain} .

В случае Pascal-кода:
function fmMain: TfmMain;
begin
   Result := Get_main_form as TfmMain;
end;

 

 

(*) Длинный путь заключался бы в том, чтобы в каждой дочерней формы создать переменную fmMain_ типа TfmMain,

и функцию  fmMain, которая возвращает эту переменную.

И прописать в точках создания всех дочерних форм присваивания значения (объекта главной формы) этим внутренним переменным fmMain_ всех этих дочерних форм.

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

 

   

Содержание

 

ЧАСТЬ 1.    AL-IV:   Как начать  программировать

ЧАСТЬ 2. AL-IV:   Создание  программ с графическим пользовательским интерфейсом

ЧАСТЬ 3.   Среда разработки: редактор    IDE AL4

ПРИЛОЖЕНИЕ 1. AL-IV: Магия командных файлов для запуска    компилятора

ПРИЛОЖЕНИЕ 2. Постепенный переход на AL-IV в    существующем проекте

Содержание

 


В начало