4. ФОРМАТИРОВАННЫЙ ТЕКСТ

Текстовый массив t() -- это массив символов, но не старых ASCII символов, а юникодов (двухбайтовых символов). Его элементам можно присваивать (вписывать) символы любого языка (юникоды), числа в текстовом формате, просто текст и многое другое. Для записи в текстовый массив существует команда #print или короче #pr.

.

 #pr FT

Она имеет один агрумент, называемый formatted text (FT). FT -- это в общем случае сложный форматированный текст, состоящий из большого числа фрагментов текста, записанных разным способом. Это может быть просто текст, а может быть и текст, генерируемый текстовой командой (форматом). Форматы, как, например, в языке Fortran, в языке Java отсутствуют, это мелкое дело и создатели Java считают, что форматы должны делать сами программисты. Но не всем интересно делать форматы, да это и неудобно в языках быстрого программирования, каким является ACL. Поэтому я сделал много разных форматов, на все случаи, но если кто-то скажет, что ему не хватает, могу без труда сделать и другие форматы. Пока есть все, что лично мне нужно для тех программ, которые я уже написал.

Прежде всего важно знать, что FT всегда заканчивается командой окончания. Все команды форматов начинаются с символа [ \ ], после которого стоит одна буква (имя команды) и вслед за ней могут быть аргументы. Команда окончания имеет вид \E без аргументов, например команда

 #pr ab cde \E

напечатает в текстовый массив t() текст (ab cde ). Как вы уже догадались, простой текст начинается с любого символа, отличного от пробела. То есть в таком режиме невозможно записать пробелы в начале текста. Как это делать будет сказано позже. Каждая команда #pri печатает в t() последовательно запись за записью, записи начинаются с t(1). Но такой естественный порядок можно изменить. Реально номер элемента массива t(), начиная с которого будет сделана очередная запись, определяется элементом служебного массива s(3) без имени. Значение этого элемента, в отличие от элементов с именами, автоматически меняется при каждой записи, все время указывая на начало следующей записи. Но это значение можно изменить и в программе, присваивая s(3) любой индекс перед выполнением команды #pri. Кроме того, для удобства использования записей после каждого выполнения команды #pri элемент служебного массива s(4) содержит начало произведенной записи, то есть индекс первого элемента текстового массива, а s(5) -- число записанных символов. Следующая команда -- это команда записи в текстовый массив элементов самого текстового массива. Она имеет два аргумента

 #pr ab \T<b> <l> cd\E

Здесь аргументы <b> (beginning) и <l> (length) -- это числа, которые указывают на первой индекс текстового массива (имя записи) и на длину текстовой строки для записи, то есть число символов. Аргументами могут быть просто целые числа, переменные или элементы числовых массивов. Опять отмечу, что после команды \T (а точнее после всех команд) пробелы игнорируются и последующий простой текст начинается с любого символа, отличного от пробела. Например,

 #pr ab \T121 10 cd\E

запишет следующий текст [ab t(121)...t(130)cd]. Вы уже догадались, что такая текстовая команда позволяет выполнять любые манипуляции со строками текста, хотя самого понятия текстовой строки в языке ACL нет. Это особенно полезно при автоматической генерации текста в циклах. В августе 2020 года я сделал дополнение к возможностям данной команды. Дело в том, что очень часто удобно записать форматированный текст с помощью данной команды, а затем использовать его в других местах. Это делается очень просто, если записать \Ts(4) s(5), то есть вместо чисел записать параметры только что выполненной записи. Но это все таки долго писать. Я сделал сокращение и то же самое можно записать как \Tp. То есть вот в таком коде

 #pr some text\E  #pr \Tp\E 

Вторая команда просто сделает копию того, что напечатала первая команда. Но копии удобно печатать не в самом тексте, а в параметрах, например, в именах файлов.

Следующая серия команд -- это команды записи в текстовый массив значений числовых переменных. Самая простая из них \G не имеет форматных аргументов, но может иметь сколько угодно аргументов, разделенных пробелами, которые как раз выводятся на печать. Список аргументов заканчивается знаком [;]. Например, правильная команда

 #pri \G a b c d;\E

Здесь a, b, c, d -- это числовые переменные. Пусть например, a=345; b=0.001; c=2.E-4; d=0; После выполнения указанной выше команды будет записан следующий текст

   3.4500+02  1.0000-03  2.0000-04         0.

Из этого примера следует, что формат \G -- это общий (general) или стандартный формат, который все числа записывает в строку из 11 символов с пятью значащими цифрами, с десятичным разделителем в виде точки и с показателем степени без знака E. Я заметил, что знак E необходим при задании чисел в математических выражениях, но при распечатке чисел через пробел он является лишним и его можно опустить, что и сделано. Такой формат удобен, если вам нужно получить значения чисел, а фасон вам не важен. Однако если фасон важен, есть другая команда

 \N<t> <f> a b c; ,

имеющая два дополнительных форматных аргумента. Здесь <t> -- число, указывающее полное число символов при печати чисел, а <f> -- число, указывающее число символов (размер) в дробной части при записи чисел. Показатель степени при этом отсутствует. Все остальное как в команде \G. Очевидно, что <t> должно быть больше чем <f> не менее чем, на две позиции + длина целой части числа. Однако есть специальные случаи. Если <t> равно 0, то длина записи числа минимальна и зависит лишь от величины целой части. Если <t> равно -1, то данная команда эквивалентна \G. Так исторически сложилось, что команда \G была введена позднее как замена этому режиму. Дополнительно есть еще формат

 \B<t> <f> a b c; ,

где аргументы имеют то же самое значение, как в и команде \N, но число записывается с одним целым разрядом и с показателем степени десяти после буквы E. Этот формат необходим для совместимости записи данных с другими программами. В некоторых программах удобно вставлять в текст целые числа с фиксированным числом разрядов. Для этого есть команда

 \I<n> a b c; ,

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

 \S a; ,

которая записывает число с минимальным числом разрядов и, кроме того, округляет последнюю значащую цифру, чтобы ликвидировать ошибки расчетов. Например, число 2.49999234 будет заменено на 2.5 так же, как и число 2.50000123. Формально эта команда тоже применяется к списку переменных, хотя она разрабатывалась для показа чисел на графиках, а значения писались слитно (без пробелов). Однако потом были добавлены к каждому числу два пробела, один спереди и один сзади, так что список переменных писать можно. Еще одно ограничение состояло в том, что дробная часть числа принудительно ограничивалась 4 знаками с округлением последнего разряда. По этой причине такой формат хорошо использовать для чисел порядка единицы, то есть не очень больших и не очень маленьких. Данный формат получается из текстового представления числа в языке Java после обработки. Но для некоторых целей можно выводить такой формат и без обработки. Это делает команда

 \O a; ,

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

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

 \U n n n*m n n; .

Она не имеет форматных аргументов. Пробел после буквы U необязателен. Конструкция n*m означает, что юникод с номером n будет напечатан m раз. Список заканчивается символом [;]. Вот теперь ясно, что 5 пробелов в самом начале текста можно ввести как \U32*5; . В команде \U аргументами могут быть целые числа, переменные и элементы массивов. При этом аргументы преобразуются в символы, а число повторений округляется до ближайшего целого. Есть, однако, модификация этой команды \u, записываемая также

 \u n n n*m n n; .

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

 \b (backspace) 
 \t (tab) 
 \n (line feed) 
 \r (carriage return) 
 \' (символ ') 
 \" (символ ")
 \\ (символ \) 
 \@ (символ @) 
 \# (символ #) 
 \[ (символ [) 
 \] (символ ]) 
 \- (ничего).

Эти команды за исключением последней вводят те символы, которые указаны вторыми, так как непосредственная запись этих символов будет приводить к неправильной интерпретации и ошибкам. Все эти символы можно ввести через юникоды, но они были в языке C и часто более наглядно их записывать так. Последняя команда \- совсем ничего не делает. Но она все же необходима, так как не только пробелы, но и невидимые знаки конца строки игнорируются после каждой команды. Очень длинный текст в аргументе команды #print набивать в одной строке неудобно и его разумно переносить. Но тогда запишется признак переноса строки. Чтобы этого не случилось, перед переносом нужно набить \- и тогда знаки переноса строки в текст не запишутся, а сама команда ничего не добавит. А если на самом деле нужно, чтобы признак конца строки записался, то пишите смело в несколько строк -- так и будет напечатано.

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

 \D ,

вставляет в текст текущие дату и время по данным на компьютере, следующая команда

 \P<n> ,

вставляет значение текстового параметра по его номеру n. Текстовых параметров 4, но изначально было 6, поэтому они имеют номера со скачком. Можно сказать, что два номера зарезервированы. Так [fir] (first) имеет номер 1, [op] (operation) имеет номер 4, [file] и [form] (format, formed) имеют номера 5 и 6 соответственно. Есть также команда

 \F ,

которая вставляет в текст имя программы-интерпретатора. После того, как появился интерпретатор в виде проигрывателя, он может иметь любое имя и это имя иногда необходимо печатать. Наконец есть совсем специальные команды. Так

 \H ,

вставляет в текст имя папки вместе с символом "/" в конце текста, которая является рабочей в данный момент, то есть после того, как она была переопределена командой #f [op=fold;] (подробности в 8-й главе). До 26 июля 2020 года был другой вариант этой команды, когда она ставила папку ACL программы, которая запускалась. Обычно такая папка известна при написании программы и ее можно заказать (сделать рабочей, см. далее) в явном виде. Но затем, при переименовании папки или переносе программы, ее текст нужно было переписывать. Используя данный формат папку можно было указать неявным образом, получая строку прямо от интерпретатора. Но если одна программа вызывала другую программу из файла, то новая программа могла находиться в другой папке, и команда не могла быть использована для определения папки конкретно работающей программы. Сейчас ситуация исправлена в том плане, что в новой программе можно один раз определить папку программы и больше ее не нужно переписывать. Данный формат все покажет. Но могут быть проблемы с программами, написанными до этой даты. В специальном варианте интерпретатора (см. главу 25) эта команда просто ничего не делает, так как в нем одна программа запускается из главной папки и вставлять ничего не надо. Это удобно для совместимости ACL программ при работе в среде разработки и в спец. варианте. Иногда необходимо знать также полный путь к папке самого интерпретатора (среды разработки). Этот путь вместе с символом "/" в конце дает формат

 \M ,

Наконец формат

 \L ,

имеет специальное назначение. Он передает в программу специальную строку из среды разработки. В данной версии эта строка заполняется при выборе в меню среды разработки кнопки [Run/File Viewer]. Пользователь может выбрать файл в любой папке любого жесткого диска компьютера с расширениями wma, wmv, mp3, mp4, avi, flv. После этого автоматически запускается ACL программа со специальным именем "pro/runext.acl", которая может производить с этим файлом некоторые действия. Она получает строку с именем файла с добавлением буквы m в первой позиции. Вот этот формат как раз и используется для передачи в программу полного имени выбранного файла. ACL программа проверяет наличие буквы m и если она есть, то формирует bat-файл с именем файла, а затем запускает его. При этом автоматически запустится проигрыватель, связанный с этими расширениями. Использование ACL программы упрощает программирование данной операции. В дальнейшем возможны другие применения этого формата.

Есть еще скобки комментария

 ![...]! .

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

Как я уже отмечал, такая совокупность форматов позволяет охватить все необходимые ситуации. Текстовый массив можно просмотреть после выполнения программы из меню оболочки [Exec/Show textarr], так как после выполнения программы записанная часть текстового массива спасается в файл с названием "textarr.txt". Вот этот файл и показывается в редакторе текста. Размер записанной части текстового массива определяется параметром s(6). Если в текстовый массив записано очень много текста и нежелательно его записывать в файл "textarr.txt", так как это занимает время, то можно просто обнулить этот параметр перед окончанием программы. Так такой файл не нужен при использовании проигрывателя.

Есть другая возможность показа форматированного текста без записи в текстовый массив. Для этого служит команда #message или короче #m. Эта команда показывает форматированный текст различным образом в зависимости от значения параметра [op]. Все режимы этой команды показывают текст в процессе работы программы как раз при ее выполнении. Если задана команда

.

 #m [op=txt;] FT,

то текст будет показан в окне текстового редактора, который сопровождает работу программы и называется "Терминалом". Замечу, что в нормальном режиме работы программы окно терминала не появляется сразу и открывается только при первой записи в него. Если записей нет, то окно совсем не видно. А после выполнения программы окно терминала автоматически закрывается. Если необходимо блокировать закрытие терминала, то перед окончанием программы надо выполнить команду #rob [mo=2;]. Если

.

 #m [op=rtt; n=1;] FT,

то в тексте, ранее набитом в терминале будет удалено столько символов, сколько указывает значение параметра [n] (number) (в показанном варианте 1). В этом случае аргумент не используется, но он все же должен присутствовать хотя бы в пустом виде \E для соблюдения синтаксиса. Этот режим позволяет контролировать степень выполнения некоторой процедуры в цикле. Можно сначала напечатать некую строку текста, а затем по мере выполнения цикла вычеркивать символы, то есть делать обратный отсчет. Если

.

 #m [op=win;] FT,

то текст будет показан в отдельном окне и работа программы будет остановлена до тех пор пока пользователь не нажмет клавишу [OK]. Если

.

 #m [op=oce;] FT,

то текст будет показан в специальном окне, содержащем три клавиши [OK] [Cancel] [Edit] и номер нажатой клавиши будет равен значению специальной переменной [&]. Если

.

 #m [op=yno;] FT,

то текст будет показан в специальном окне, содержащем две клавиши[Yes] [No] и номер нажатой клавиши будет равен значению специальной переменной [&]. Команда

.

 #m [op=uni;] FT FT, 

имеет два аргумента FT и показывает сообщение в окне, атрибуты которого определяются вторым аргументом FT. Первый аргумент FT, как обычно, задает сам текст сообщения. Второй аргумент FT должен содержать несколько текстов, разделенных знаком вертикальной черты [|]. При этом первый текст -- это заголовок самого окна, а остальные -- это заголовки кнопок, число кнопок будет зависеть от числа записанных текстов. Номер нажатой кнопки в диапазоне от 1 и до номера последней кнопки возвращается в [&]. Все кнопки располагаются в один ряд.

В процессе развития языка ACL появилась более сложная команда

.

 #m [op=gen; b=; nx=; ny=; siz=; n=;] tit\E  text\E  butt\E  

Она выставляет окно сообщения на экране вместе с произвольным числом кнопок, которые могут располагаться в несколько рядов. Аргументы команды очевидны: первый задает название окна, второй - текст сообщения, третий названия кнопок. В тексте сообщения может присутствовать символ \n разделяющий строки, но строки не должны быть пустыми. Пустую строку надо задавать в виде \u32;\n. Названия кнопок разделяются символом [ | ]. Параметр [b] указывает индекс первого элемента целого массива i(), в котором должны быть записаны числа, регулирующие расположение элементов в окне. Число таких чисел должно быть согласовано с аргументами. Так, если в аргументе text есть n1 строк, а параметр [n] равен n2, то чисел должно быть N=n1+2*n2. Первые n1 чисел задают размеры твердого пустого пространства, устанавливаемого после каждой строки текста сообщения. Дело в том, что строки автоматически центрируются. Если же необходимо их выравнивать по левому краю, то нужно удлинять короткие строки справа. Если же это не нужно, то можно задавать нули. Параметр [n] указывает число строк, в которые будут размещены кнопки. Поэтому следующие за n1 ровно n2 чисел, указывают сколько кнопок надо разместить в каждом ряду. Очевидно, что сумма этих чисел должна быть равна полному числу кнопок. Наконец последние n2 числа указывают размер полей справа и слева в каждом ряду кнопок. Это полезно, чтобы длина кнопок не заполняла весь ряд, что часто выглядит некрасиво. Параметры nx, ny задают позицию верхнего левого угла окна относительно левого верхнего угла экрана. Если хотя бы один параметр отрицателен, то окно помещается в центре. Наконец параметр [siz] указывает размер полей со всех сторон окна, куда не могут попасть ни текст, ни кнопки. Как обычно, команда возвращает в [&] номер нажатой кнопки

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

Аргумент в виде форматированного текста используется практически во всех командах, в которых надо определить текстовую строку. Это общая конструкция, которая не ограничивается описанными в этом разделе командами ACL. Поэтому полезно здесь привести условную формулу для форматированного текста, включающую все форматы

 FT == ...\b ...\t ...\n ...\r ...\" ...\' ...\\ ...\- ...\# ...\@ ...\[ ...\] ... \D ...\T<ifc> <nc>
   ...\U n n n*m ; ...\u n n*m ; ...\I<nt> n n n; ...\N<nt> <nf> n n ; ...\G n n ; ...\B<nt> <nf> n n ;
   ...\S n; ...\P<nt> ...\F ...\H ...\M ...\L ...\E