3. ПЕРВЫЕ КОМАНДЫ

Начнем описание команд по принципу -- сначала самые важные и простые, затем все остальное. Прежде всего есть пустая команда #parameters или сокращенно #p. Она сама ничего не делает, но, как и для любой другой команды, после нее можно писать поле определения параметров (FPD). И как раз для этих целей она и используется. Иногда это бывает удобно. Итак

 #p [n=1; b=1; le=1; c=1; ...]

Здесь для примера указаны некоторые часто используемые параметры [n] number, [b] begin, [le] length, [c] code. Каждая команда использует свои параметры и они будут указываться по ходу описания команд. Полная таблица всех команд и параметров дана в 24-й главе. Далее, есть команда окончания работы программы

 #stop

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

 #exit

позволяющая полностью выйти из Java программы интерпретатора, которая обеспечивает работу ACL программы в независимом варианте. Она необходима только при запуске интерпретатора с полностью готовой ACL-программой, когда среда разработки ACL-программ не используется совсем. Это позволяет представить ACL-программу как независимую Java программу, при использовании которой знание языка ACL не требуется. Начинающим программистам этой командой лучше не пользоваться. Далее, в языке есть описания процедуры

 #pro NAME  <здесь помещаются все другие команды> @

Символ [@] служит окончанием процедуры (жирная точка). Имя процедуры NAME является первым аргументом такой команды. Оно должно содержать 4 знака в любой комбинации. Любой кусок программы можно предварительно поместить в тело процедуры, и он при этом не выполняется, а запоминается. Тело процедуры и символ окончания [@] можно рассматривать как остальные аргументы команды. Код в теле процедуры будет выполнен позже, при вызове процедуры. Порядок записи на строке не имеет значения. Как удобно, так и записываете. Процедуры выполняются с помощью специальной команды, которая должна, естественно, быть поставлена после определения процедуры

.

 #e [c=1;] NAM1 NAM2 NAM3  #%

Эта команда как раз выполняет (execute) процедуры одну за другой из указанного списка. Если у команды #pro есть только аргументы: [NAME] и сама процедура, то у команды #e кроме аргументов есть уже и параметр с именем [c] (code), значение которому можно присвоить прямо тут же, в FPD, а можно и раньше. Все процедуры выполняются только в том случае, если значение параметра [code] совпадает с текущим значением переменной [&]. Эта переменная должна быть определена заранее. Но если написать

 #e [c=&;] NAME  #%

то процедура всегда выполнится при любом значении [&]. Для сокращения записи, то же самое можно написать как

.

 #e _NAME  #%

Символ подчеркивания перед первым именем в списке процедур означает безусловное выполнение. Важно помнить, что [c] -- это целое число, а [&] - это вещественная переменная, поэтому для сравнения берется ее ближайшее целое.

Эта команда реально имеет очень большое значение, потому что используется часто и не только с процедурами, записанными явно. Есть два специальных режима работы этой команды, необходимые для написания особенно сложных программ. Специальные имена процедур [file] и [text] служат для выполнения команд программы из файла или из текстового массива t(). Пример:

.

 #e [file=pro/calcul.acl;] _file 

Эта команда выполнит набор команд ACL, записанных в файл "calcul.acl", помещенный в папку "pro" внутри главной папки интерпретатора. Интерпретатор первоначально был сделан так, что он не работал с внешними папками, а работал только с папками внутри "своей" папки, то есть папки, в которой находится сам интерпретатор, то есть файл (vkACL.jar). Папка -- это место, где хранятся файлы, другое ее название -- Директория -- использовалось в ДОСе, и иногда продолжает использоваться, а я перешел на оконный язык. Здесь уже используется второй текстовый параметр [file] для указания пути к файлу. В этой команде путь к файлу указывается полный, то есть относительно папки интерпретатора. Это необходимо по той причине, что имя текущей рабочей папки может использоваться для других файлов. С другой стороны, иногда полезно держать все файлы с процедурами в одном месте независимо от прикладной программы. Процедуры, помещенные в файлы, могут быть относительно универсальными и могут использоваться многими программами. Поэтому они должны удовлетворять некоторым ограничениям поскольку интерпретатор использует одни и те же ресурсы для всех программ. Но можно и просто поместить в файл любой кусок программы и затем выполнить его.

В процессе развития программы я отказался от локализации файлов внутри папки интерпретатора во многих командах работы с файлами, в том числе и в этой команде. Если полный путь к файлу будет начинаться так C:/... или так D:/... , то есть буква диска, двоеточие и так далее, то команда будет работать, но в этой команде осталось ограничение имени файла 42 символами, а конструкция file=arg; не работает. То есть надо стараться не использовать папки с длинными именами. Еще более сложная команда

.

 #e [b=a; le=b;] _text 

выполняет команды, динамически записанные в часть текстового массива t(), начиная c элемента t(a) и длиной b символов. Понятие строки текста в ACL не существует. Любая строка, как известно, состоит из набора символов и имеет имя и длину. Значения числовых параметров [b] (begin) и [le] (length) можно рассматривать как имя и длину строки. Просто в ACL в качестве имени строки используется число, которое указывает начало размещения символов строки в текстовом массиве. Этого вполне достаточно. Программа, которую выполняет данная команда, исходно не существует, поэтому ее надо предварительно записать. Естественно и параметр [c] тоже можно использовать в обоих случаях. Записанный вариант безусловного исполнения просто короче.

Наконец, нужно отметить еще одно важное свойство этой команды. Она читает имена процедур для выполнения неограниченно, пока не встретит символ [ #] или символ [@], означающие начало новой команды или окончание процедуры. Исключение составляют только специальные имена file и text. Ни до, ни после них никакие другие процедуры не выполняются. Поэтому они не могут быть в цепочке. Если после команды необходимо вставить текст комментария или данная команда является последней в файле, то после нее можно поставить любую другую команду с фиксированной длиной. Самой короткой командой является #% поэтому проще всего использовать эту команду. Но для сокращения записи то же самое делает символ ( ! ) восклицательного знака. Если этого не сделать, то интерпретатор выдаст ошибку несуществующей процедуры.

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

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

 #pro main ... @

Теперь уже можно писать любые процедуры в любом порядке, а в конце программы написать стандартную строку

 #e _main   #stop  или   #e _main  #% 

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

Выполнение команд из файла часто бывает очень удобным приемом, потому что такую процедуру не надо переписывать в каждую программу. Допустим, вы разработали некий универсальный код, который выполняет определенную работу над данными. Достаточно поместить этот код в файл, приготовить нужные данные и просто запустить процедуру. Так как таких процедур со временем может накопиться много, удобно сократить для них способ их вызова. Такой аппарат действительно развит в виде вызова суперкоманды. Cуперкомандой называется специальным образом организованная процедура, которая записана в файл "name.acl", где "name" - любое имя, и помещена в папку "proc", которая специально создана для аккумуляции суперкоманд. Все файлы из папки "proc" можно запускать на выполнение конструкцией, похожей на команду, а именно ##name -- то есть перед именем файла без расширения надо поставить два символа [ #].

В отличие от обычной команды, такая суперкоманда не может определять ни параметры, ни аргументы. Но параметры она может наследовать от команды #p [...], а аргументы можно предварительно напечатать в текстовый массив t() командой #pri (см. далее), из которого суперкоманда их прочитает. Таким образом, можно оформить суперкоманду с входными параметрами, выполняющую некоторую общую работу. Вот пример. Команда #w (см. далее) имеет очень много параметров. Можно выделить из них важные, а остальные определить раз и навсегда и сделать суперкоманду, которая будет иметь меньше параметров. Дополнительно можно включить в нее определенные процедуры предварительной обработки данных. Но суперкоманда может иметь форму и самой обычной процедуры. Другими словами, мы просто заменяем вызов #e [file=proc/name.acl;] _file на ##name. Такая замена очень хорошо упрощает программирование.

Очевидно, что суперкоманды можно создавать по ходу разработки какой-либо программы. Их можно модифицировать, дописывать, изменять. Те суперкоманды, которые созданы мной, входят в стандартную поставку программы интерпретатора. Но пользователь может создавать и свои собственные суперкоманды. В этих условиях описание работы всех суперкоманд не могут входить в общее описание. Иногда разумно включать описание суперкоманд в сам текст суперкоманды, то есть в файл, в виде комментария. Каталог таких суперкоманд является частью каталога файлов в папке "proc". Очевидно, суперкоманды неразумно ставить в циклы с большим числом повторений, но их разумно использовать при разработке графических объектов, разных стандартных операций с картинками, с файлами. Более того, любую программу разумно разбить на блоки и выделить стандартный кусок, который затем можно преобразовать в суперкоманду. Это облегчит программирование в будущем.

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

Есть и еще одна специальная возможность использования команды #e . С ее помощью вызываются внешние программы, написанные полностью на языке Java и включенные в код интерпретатора как процедуры. Более подробно об этом написано в главе 33. Такую возможность использую я сам, и она годится только для Java программистов.