23. ПРИМЕР ACL ПРОГРАММЫ. КАЛЬКУЛЯТОР

В этом разделе показан один пример ACL программы, которая записана в файле [pro/comp.acl] дистрибутива программы. Другие примеры обсуждаются в других главах данного описания. Сначала я покажу весь код программы, а затем буду его комментировать.

#pro calc
#f [op=fold; file=pro;] # &=1;
#case 1  
 # Q=0; s(3)=1; #pri Выберите номер ячейки, в которой хранятся ваши формулы, \-
   и работайте с ними, [help] - информация, [exit] или [Х] - выход !\E ##mess
 #sel [nx=6; ny=9; mo=0; wid=60; hei=30; tsi=20; col=255; em=1; xs=10; ys=32;] 
  Select variant\E 
  help|01|02|03|04|05|06|07|08|09|10|\-
  11|12|13|14|15|16|17|18|19|20|21|\-
  22|23|24|25|26|27|28|29|30|31|32|\-
  33|34|35|36|37|38|39|40|41|42|43|\-
  44|45|46|47|48|49|50|51|52|exit\E 
 # S=&-1; #fr [op=c; mo=1;]  # &=(53-S)<1; 
 #case 1 # &=S<1;
  #case 0 # s(1)=10; #f [op=edit; mo=1; c=1; ys=10; fk=0; fs=16; em=11; nx=300; ny=0; file=comp.inf;] # Q=1; #end |  
  #case 1  # a=0; b=0; c=0; d=0; e=0; f=0; g=0; h=0;  #e _inpc  # Q=1; #end | 
 #end |  # &=Q; 
#end 
#f [op=fold; file=oldf;]  #fr [op=c; mo=1;]
@
#pro inpc  # &=S<1;
#case 1
 # s(3)=1; #f [op=line; n=-S; file=comp.txt; err=1;]  # u=s(5); #% 
 #case 10101   
  #d 5 i(1) 0*3 1 0
  #m [op=gen; nx=0; ny=20; b=1; n=1; siz=20;] Error\E  
   Sorry, you have typed the invalid expression.\n   Please try again.\n\u32;\E  OK\E
 #end |   # s(3)=1;
 #inp [n=8; le=170; mo=3; ysh=70; em=1; xs=10; ys=10;] 
   Calculator\E    a = |b = |c = |d = |e = |f  = |g = |h = \E   \T1 u\E  
 # u=s(5); Q=&; #fr [op=c; mo=1;]  
 #case 2 #p [err=0;]  #end | 
 #case 1  
  # z=s(5); s(3)=3999;  #te [op=repl; b=1; le=z; c=10; mo=124;] 
  #e _comp #e _text  #p [err=0;]  #f [op=line; n=S; b=1; le=z; em=0;]  
  #g [op=open; twi=100; the=200; col=246; sca=100; trx=0; try=0;]  # y=16; y1=22; n=1;
  #p [op=text; nx=10; col=247; tfo=2; tki=1; tsi=14; sty=1;] # s(3)=1; #pri h g f e d c b a \E #d 8 r(1) h g f e d c b a  
  #rep 8 # k=2*n-1; #g [ ny=y;] \Tk 2 =\G r(n);\E  # y=y+y1; n=n+1;  #end 
  #g [op=clos; sav=100;] \E 
  #fr [op=o; mo=1; n=100; xs=546; ys=42;] 
 #end |  # &=Q;
#end 
@
#pro comp
#te [op=find; b=1; le=z; n=1; c=124;]
# A=1; B=i(1)-A; C=i(1)+1; D=i(2)-C; E=i(2)+1; F=i(3)-E; G=i(3)+1; H=i(4)-G; I=i(4)+1; J=i(5)-I;
# K=i(5)+1; L=i(6)-K; M=i(6)+1; N=i(7)-M; O=i(7)+1; P=i(8)-O;
# o=s(3); #pri \#\u32;\E 
# &=B<1; #case 0 # a=0; #end | #case 1 #pri a=\TA B ; \E #end |
# &=D<1; #case 0 # b=0; #end | #case 1 #pri b=\TC D ; \E #end |
# &=F<1; #case 0 # c=0; #end | #case 1 #pri c=\TE F ; \E #end |
# &=H<1; #case 0 # d=0; #end | #case 1 #pri d=\TG H ; \E #end |
# &=J<1; #case 0 # e=0; #end | #case 1 #pri e=\TI J ; \E #end |
# &=L<1; #case 0 # f=0; #end | #case 1 #pri f=\TK L ; \E #end |
# &=N<1; #case 0 # g=0; #end | #case 1 #pri g=\TM N ; \E #end |
# &=P<1; #case 0 # h=0; #end | #case 1 #pri h=\TO P ; \E #end |
#pri \#p\u32;\[\]\u32; \E
#p [b=o; le=s(3)-o;] 
@
#e _calc  #%

Начнем изучать программу. Код программы разбит на три процедуры: главную и две вспомогательные. После этого написана одна команда, исполняющая главную процедуру. Сначала главная процедура устанавливает рабочую папку [pro], в которой находится сама ACL программа, и организует бесконечный цикл. Затем она выставляет на экран подсказку для пользователя. Это делается с помощью суперкоманды ##mess. Описание этой команды есть в главе 26. Затем она показывает таблицу кнопок размером 6*9 с именами вариантов расчетов. Имена просто равны номеру варианта. При этом первая кнопка имеет имя [help], а последняя [exit]. По первой кнопке запускается текстовый редактор для редактирования файла с именем "pro/comp.inf", в котором записана инструкция для пользователя и памятка на варианты. При выборе других номеров запускается процедура ввода формул с контролем возможных ошибок. Но так как номер кнопки и номер варианта отличаются на 1, то номер выбранного варианта предварительно запоминается в переменную S.

Процедура ввода первоначально инициирует все переменные от a до h нулевыми значениями. Затем вызывается другая процедура inpc, которая делает всю работу. Это сделано просто для удобства, так как текст процедуры можно было бы поместить на место ее вызова, поскольку она вызывается только один раз. После окончания работы процедуры, если переменная Q равна 1, запрашивается ответ на продолжение. Можно выбрать тот же самый вариант, другой вариант или отказаться. А если Q=0, то программа заканчивает сразу. Это сделано для удобства одноразового режима работы, когда необходимо выполнить только один расчет. При запросе надо снова запомнить выбор, так как переменная & будет испорчена в конце case-условия. А затем снова восстановить значение & для реализации запроса. Если же текущий вариант был отвегнут, то надо снова проверить значение & за вычетом единицы, так как все условия case имеют код 1. Если же и другой вариант не выбран, выходим на финишную прямую и восстанавливаем старое значение рабочей папки, до последнего определения. Работа закончена.

Рассмотрим теперь основную рабочую процедуру inpc. Весь ее код тоже помещен в условие case. Вообще говоря - это перестраховка, так как S не может быть меньше 1. Основной код устанавливает курсор для записи в текстовый массив, то есть параметр s(3), на начало, а затем считывает из файла с названием comp.txt в папке pro строку с номером S, то есть номером выбранного варианта. Затем устанавливается режим нестандартной обработки ошибок, так как параметр [err] не равен нулю. Сразу же определяется переменная [%] фиксируя место, куда надо перейти в случае ошибки. А за этим местом ставится условие case с кодом 10101. Именно такое значение будет иметь переменная [&] в случае ошибки. По этому условию будет показан текст сообщения об ошибке. Наконец опять ставится курсор записи в текстовый массив на начало и выставляется панель с 8-ю окнами ввода. Третьим аргументом команды #inp указана часть текстового массива, в которую была прочитана нужная строка из файла. Это исходные тексты, которые появятся в окнах ввода. Они были набиты в прошлый раз и спасены в файл. Как раз выбор кнопки на этой панели и спасен в переменную Q.

Если пользователь выбрал кнопку [Cancel], то эта переменная продвигается дальше (с 2 на 3), а параметр [err] возвращается в исходное состояние. Он как раз равен s(26). Снова проверяется Q. Это необходимо, так как в ACL нет конструкции типа if()else() и просто нужно каждый раз определять переменную [&] заново. Если была выбрана кнопка [OK], то начинаем работу. В переменную [z] запоминаем размер записанной части t(), затем устанавливаем курсор записи подальше и перезаписывам введенный текст с заменой символа 10 (окончание строки) на символ 124 (вертикальная черта). Выполняем две процедуры с названиями make и text. Первая из них у нас есть, а вторая выполняет команды записанные в массив t(). Эти процедуры нельзя выполнить одной командой, так как процедуры с названиями file и text не комбинируются. Если при выполнении этих команд обнаружится ошибка, то управление выполнением программы перейдем назад на место перед #case 10101. А если ошибки не было, то заново введенный текст опять запишется в файл, а на экране появится сообщение с именами переменных и их вычисленными значениями. То есть результат получен.

Осталось рассмотреть, что же делает процедура comp. А она как раз формирует из набитого пользователем текста код программы на ACL. Поскольку в тексте 8 разных окон ввода и 8 переменных, то сначала в набитом тексте находятся все позиции разделителя, то есть символа 124, а затем запоминаются начала и размеры всех отдельных строк. После этого форматируется текст самой программы. Код этой процедуры тоже можно было бы сразу поставить, но разбиение на процедуры существенно упрощает чтение программы. Вот и все. То есть каждый раз формулы в окнах считываются из файла "pro/comp.txt" , а при вводе новых формул снова записыватся в этот же файл. Для контроля ошибок используется параметр [err] и команда #%. Набитые формулы записываются в текстовый массив и динамически выполняются как процедура. При обнаружении ошибки программа снова возвращается на ввод формул. Если же ошибок нет, то все 8 переменных получают нужные значения, которые показываются в новом окне сообщения в виде текста.