| Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |
три: чтение, запись и побитовое-И — например на предмет проверки признака
готовности), без первого аргумента: FX( , А, Б) не лезет ни в какие
регистры, а всего лишь выполняет побитовое-И между А и Б, рассматривая их как
длинные целые: бывает, что надо и в других местах выделять отдельные биты.
(Или, используя не вполне корректные фокусы-покусы со знаками А и Б — другие
побитовые операции...) Или например так же самая FSBr() без аргументов не
вызывая никаких подпрограмм, сразу возвращает содержимое аккумулятора. (Куда
иногда могут "зелететь" и такие вещи, как например количество строк, реально
выданных на экран просмотрщиком, что больше ну никак...)
— парочка-троечка функций с побочными эффектами: FColoro (она же FЦвет) для
указания цвета выводимых на экран символов (включая коррекцию палитры);
FKурсор (она же FCS) для перемещения по экрану курсора (включая считывание
считывание уже выведенных на экран буковок, изменение их цвета, а так же
рисование на нём линий и рамочек символами псевдографики); FBIp для издания
звуков с помощью встроенного в компьютер динамика (включая ноты и азбуку
морзе); FMuso (она же FMышь) для работы с мышкой; FMIn и FMAx (без побочных
эффектов) призванные (вместе со сменой знака в роли инверсии) служить
логическими операциями И и ИЛИ — в том числе для троичной или нечеткой логики.
FTMp для получения текущей даты/времени (в виде количества суток от начала
тысячелетия, где время это дробная часть суток) а так же для других действий с
датой/временем, включая преобразование в удобочитаемый вид и обратно. (Вот эта
вот функция была первой и получилась несколько нестандартной...)
— оператор Vizual и парная к нему функция FViz на предмет "управления
визуализацией". А на самом деле получения параметров экрана (например высоты и
ширины), а так же режима работы дисплея. Включая их переключение, в том числе в
один из графических режимов и отрисовку там графичесских примитивов.
Однако, эти примитивы оказались слишком примитивными (и пока что этот
оператор отправлен на реконструкцию, а функции сией функции — урезаны): Фокал
таки калькулятор, и графика ему нужна чтобы можно было рисовать графики -
компактно и наглядно отображать результаты вычислений. За сим графическими
примитивами должны быть вовсе не "точка", "линия", "дуга окружности",
"полигон" и закраска оного, а оси координат (вместе с началом координат,
масштабом по каждой оси, в том числе, возможно, нелинейным, и делениями на ней)
и уже только после этого точки графика (возможно объединённые в "коллекции"),
положения которых на экране автоматически пересчитываютя в соотвтествии с
масштабом осей. Эта часть графики — "векторная". А "растровую" предполагается
поручить двум функциям FТочка и FЛиния, как это было в Фокале на БК-0010,
организованным по аналогии с FKурсор...
— некоторая модернизация некоторых операторов:
* Вычисление возвращаемого значения прямо в операторе Ret, делающее его
аналогом Xecut. (Чисто на будущее: чтобы если и когда будут параллельные
процессы, запускаемые оператором Job — чтобы между вычислением возвращаемого
значения и возвратом из функции не вклинилось что ни будь, что испортит нам
всю малину.)
* Передача оператором Do параметров в подпрограмму по аналогии с FSBr
* Дополнительные ключевые слова в операторе Write чтобы сообщал дополнительные
сведения (в форме пригодной для последующего ввода), в том числе о результатах
деятельности операторов Set Oper Do Break... Аналогично и для Eraze — буде
там найдётся что очистить.
* Несколько выражений в операторе Xecut и несколько присваиваний в операторе
Set — выпендрёж чистой воды. (Ибо экономия получается — копеечная.) А вот
избавляться от ключевого слова Set (как в Бейсике первое что сделали — сделали
чтобы можно было не писать LET) — это фиг: нарушение принципов! Да и экономия
в два символа, включая пробел...
* Меры по повышению "скриптовости" операторов передачи управления If и Go.
Это когда программа не как обычно — сперва грузится в память и только потом
запускается на выполнение, а сразу выполняется по мере чтения из файла. Который
называют "командным" (а нынче — "скриптовым"). Особенность тут в том, что
все строчки командного файла — "прямые". А операторам передачи управления
подавай номер строки!. Чтобы от них здесь был какой-то толк, надо бы номера
строк как ни будь того... Равняясь на оператор For, у которого тело цикла это
остаток строки, вспомним, что и у If есть то же самое — когда последние адреса
перехода отсутствуют. Ну так разрешим, чтобы любые, а не только последние -
при условии сохранения разделяющих их запятых. И плюс к этому пусть нулевой и
отрицательный номер строки тоже что-то значат: нулевой — ничего не делать
(перейти к следующей строке), а отрицательный — к следующему оператору, как и
пропуск. (А то вызовем FSBr, а она...) И тогда можно например так:
If (X) 0, ,0; Type " икс равен нулю "!
If (X) ,0 ; Type " икс не равен нулю"!
Дополнительно: из трёх выражений в операторе If теперь вычисляется только одно,
а остальные — пропускаются. Потому что эти выражения вполне могут давать
побочный эффект. И/или в выборе одного из них — смысл всего этого оператора...
По аналогии с If — оператор Go 0; передаёт управление на начало текущей
строки и таким образом позволяет сделать цикл в одной строчке. Например:
Set c=FCHr(-1); type c; If(c-27),0; Go 0; Coment 27 — код нопки ESC
Эта програмка в одну строку будет выдавать коды нажатых кнопок, пока
пользователь не нажмёт кнопку ESC, она же "эскейп".
* Модернизация оператора For на предмет борьбы с плавающей арифметикой:
сделано так, что цикл завершается, когда параметр цикла соберётся выскочить за
конечное значение более чем на пол шага. (Но после завершения цикла остаётся
таким, каким был при последней итерации.) Ну и за одно — автоматический выбор
шага, если он опущен: еще и -1 если конечное значение меньше начального. А
опустить можно не только шаг, или даже конечное значение (получится аналог
оператора присваивания), но и вообще всё. Остаток строки выполнится ровно один
раз, но как подпрограмма — что нам тоже понадобится... (Чуть ниже.)
— Реакция на "события" и "ситуации" (в т.ч. ошибки). Она устанавливается:
Break С = реакция; "Реакция" здесь это номер строки или группы, которую
надо запустить, когда произойдёт оное событие или случится ошибка/ситуация.
Хотя это может быть и остаток строки: Break С = ; остаток строки...
Если С < 0 то это ВНЕШНЕЕ "событие", ловушка на него — глобальная.
(Удалить — только явно, указав нулевую реакцию.) Для ДОС`а первые 256 из них
реальные прерывания (а под UNIX`ом это будут сигналы); с номерами больше 1000
— свои собственные, типа окончания звукового фрагмента, временного интервала,
заказанного функцией FCLk, и.т.п. К сожалению количество таких ловушек очень
ограничено — средство это таки экспериментальное. Интерпретатор Фокала -
медленный; реакция на событие "вклинивается" между выполнением операторов и
выглядит так, как будто между ними вставили оператор Do, но когда это еще
будет... Поэтому внешние события только "фиксируются" — наращивается значение
связанного с ловушкой счетчика. При реакции оно передаётся первым аргументом,
а счетчик — сбрасывается. Принудительно обнулить все эти счетчики: Eraze Break;
Если С >= 0 то это ВНУТРЕННЯЯ "ситуация", в том числе ошибка; ловушка
на неё — локальная. (Автоматически удаляется при возврате из поставившей её
подпрограмы вместе с локальными переменными.) По аналогии с программными
строками, события объединяются в группы (ошибки: группы событий 0 — 5), ловушку
можно поставить как на всю группу, так и индивидуально. Возникнув, ситуация
начинает "распространятся" — последовательно прекращая выполнение вложенных
вызовов подпрограмм. И дораспространявшись до интерпретатора, вызывает с его
стороны нелицеприятную реакцию. Но буде одна из подпрограмм поставила
подходящую ловушку — она срабатывает; запускается подпрограмма реакции, которая
якобы и исправляет ошибку. После чего столь предусмотрительная подпрограмма
нормально завершается — возвращает управление в точку вызова.
Искусственно порождать ситуации поручено оператору Quit (а события — Kill).
Например так можно досрочно выскочить из цикла или даже нескольких вложенных:
Brek 7; For i=1,N; For j=-M,M; For k=0,L; If(FSBr(ххх, i,j,k))0; Quit 7,""
Вот как подпрограмма по адресу ххх вернёт положительное число, показывая что
переданные ей i j k её вполне устраивают, так и. Это и есть "структурный
переход". Ситуация 7 выбрана "от балды" (лишь бы не совпадала с уже имеющимися:
теми, которые ошибки). Дололнительные числовые аргументы в Quit передаются
подпрограмме реакции, но она в этом примере — "нулевая". А вот текстовый -
интерпретатору, чтобы он, если что, знал что сказать. А в нулевой строке (как
в данном случае) указывает — что мол еще поработаем, что это не команда на
завершение работы интерпретатора.
Если вышеприведённый пример в одну строку, таки строка подпрограммы, то
следующие после неё строки не будут выполнены: ведь тут же случилась СИТУАЦИЯ,
но реакция на оную (хотя и нулевая) героически устранила последствия. После
чего подпрограмма НОРМАЛЬНО завершается, а не... (Типа: не устрани она — ой что
было бы!) Ага-ага. Но если нам надо чтобы выполнились и следующие строки, надо
засунуть всё это в персональную подпрограмму, сделав телом оператора For из
одного только этого ключевого слова. Вот пусть это она "нормально завершается".
— В дополнение к трассировке и пошаговому режиму, которые были всегда, с
одной стороны отладочное окошко (правда весьма ограниченной полезности, так как
пристойно работает только в текстовых режимах) — чтобы трассировочная
информация попадала туда и не на основной экран и не портила изображение;
а с другой — микро-хелп в отладочном режиме (подсказка по его командам) и
возможность ввести и выполнить командную строку — чтобы например посмотреть
значения переменных или заглянуть в основной хелп...
А вот перенаправление трассировочной информации в отдельный файл — тот,
который указывается в командной строке вторым и открывается под псевдонимом Б,
так и не сделано: уж больно как-то оно всё неизящно получается...
— Табулостопы и спецкомментарий из одних двоеточий, типа: : : : !
где двоеточиями отмечаются их позиции. Спецкомментарий становится "спец" только
если завершается ! (восклицательным знаком) или ; (точкой с запятой),
указывающими на конец строки или же её продолжение. Иначе, как и любой
комментарий, игнорируется. (Раньше двоеточие тоже числилось буковкой на ряду со
всякими # @ $ | ~ но поручив ему табуляцию, пришлось назначить
его разделителем.)
Вобще-то табулостопы понадобились оператору Write со вторым ключевым
словом Set, сообщающему результат деятельности оператора присваивания — список
переменных, имеющихся на настоящий момент в памяти. Вместе с их значениями,
разумеется. Этих переменных может быть как две-три, так и десятки, сотни и
даже тысячи, особенно когда мы имеем дело с массивами. И выдавай оператор Write
каждую из них в отдельной строке — просматривать всё это было бы муторно.
Надо чтобы в виде таблички, желательно стройными рядами и колоннами... Ну так
на то и табуляция!
Секретарши испокон веку печатали на пишущих машинках всяческие таблички.
И у них там эти самые "табулостопы" — такие выдвигающиеся железочки,
отмечающие начало очередной колонки. А клавиша ТАБ передвигала каретку к
следующему. Но в эпоху алфавитно-цифровых дисплеев их тупо расставили в каждую
восьмую позицию... А я сперва сделал чтобы можно было устанавливать какой хочу
шаг табуляции, а потом и оные табулостопы индивидуально. И свалил всё это на
FVIz. Получилось универсально, но таки сложновато и ненаглядно. А наглядно — в
виде вот такого спецкомментария. Он же выдаётся по Write Tab; а Eraze Tab;
приводит систему с состояние по-умолчанию.
И теперь вот думаю: а ведь запись в базе данных, ну например типа .dbf,
она ведь вот так же выглядит? Правда, там у полей есть имена, и их границы
пересекать не полагается... А что мешает и мне так сделать? И можно будет
заполнять поля оной записи в произвольном порядке, типа: Type :имя, значение;
Правда, для этого понадобится еще и буферизация вывода...
* * *
Подсистема ввода/вывода Фокала (ну наконец-то мы до неё добрались!)
устроена очень просто: есть один канал ввода и один канал вывода. Канал вывода
обычно направлен на терминал, за которым и сидит пользователь, но может быть
переключен оператором Operate куда-то еще. А канал ввода соответственно
по-умолчанию подключен к клавиатуре.
Из канала ввода читает функция FCHr — побайтно, оператор Ask — построчно,
и интерфейсная часть интерпретатора (тоже построчно), когда ей нужна
очередная командная строка.
Обратим внимание: интерфейсная часть интерпретатора читает командные
строки из канала ввода, не интересуясь — к чему именно он подключен. Что и
даёт возможность как загрузить ранее сохранённую программу (просто переключив
на неё канал ввода — будет вводиться сама собою, пока не кончится...), так и
выполнять командные ("скриптовые") файлы — в точности так же. Отличаются
только тем, что тут все строки — "прямые", а там — косвенные. То есть ничем:
ничто не мешает как добавить после программы прямую строку, которая например
её сразу же и запустит, так и командному файлу по мере необходимости
подгружать (а потом — удалять) куски программ. (Сильно сомневаюсь, чтобы
Бейсику было доступно хоть что-то подобное.)
Кстати, при запуске интерпретатора, первый аргумент в командной строке
это имя файла, который сразу же открывается (под псевдонимом "А") и на него
переключается канал ввода...
В канал вывода пишут все, кому не лень: и та же самая функция FCHr — тоже
побайтно; и операторы Type, Write, Help; и сам интерпретатор — сообщения об
ошибках; и даже функция FTMp. (Прямо не канал, а проходной двор!)
Но за то, в отличии, например, от Бейсика, где и для вывода программы
"на посмотреть" пользователю, и для сохранения её где-то на внешнем носителе
используются разные команды — LIST и SAVE, каждая со своим собственным
заковыристым и неочевидным синтаксисом, то в Фокале всё это делает один и тот
же оператор Write, синтаксис которого предельно прост. Но конечно для
| Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |