Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |
поредактировать, и то что получилось сбрасываем в другой файл (когда придумаем
средство вывода). Ага, разбежались! При переключении канала ввода вот с того
самого файла на терминал, А2 автоматически очищается. Ну так надо чтобы не
очищался: добавим ко всяким RWABT в псевдониме открытого файла еще и буковку N.
А вот мы хотим, чтобы это было число, которое вот сейчас и вычислим...
Для этого переведём оператор Ask в особый режим, когда он работает в точности
как Type, но пишет не в канал вывода, а в А2. С помощью "спецформата" %% тоже
очищающего А2 и спецформата %%% — не очищающего (только урезающего по текущую
позицию маркера) — чтобы можно было добавить к тому что там уже есть.
Действует этот особый режим работы оператора Ask до его конца или до ! как
раз и означающего конец строки.
Забегая вперёд: автор строит хищные планы не ограничивать режим вывода в А2 по спецформату %%% концом оператора Ask. Дабы приобщить к нему и всех остальных, кто способен писать в канал вывода. А то есть вот такая мелкая проблемка: исторически так сложилось, что функция FTMp, сообщающая текущие дату/время в виде единого числа, сама же и преобразует его в удобочитаемую форму. И этот текст выдаёт в канал вывода. В то время как все остальные функции с подобными побочными эффектами (FTEll например — имя очередног файла при их поиске в каталоге) пишут таки в А2. Вот так неединообразно получилось. Но возни, чтобы эту дату/время как то использовать... А тут всё стало бы единообразно.
Возникнув, эти самые спецформаты %%, %%% и даже %%%% принялись мигрировать,
в том числе обратно в операторы Type и Write.
Впрочем используются они там для вспомогательных целей. Вот есть у нас
такая штука — встроенный просмотрщик. (Аналог UNIX`овского more.) Всего лишь
подсчитывает переданные ему для вывода на экран строчки. И как вывел N штук,
останавливается и ждёт что по этому поводу скажет сидящий за терминалом
пользователь. А он может нажать либо ввод, тогда просмотрщик выдаёт еще одну
строчку, либо пробел — тогда следующий экран, либо ЕСЦ — тогда вывод должен
быть прекращен.
Придумано это для оператора Help когда тексты у него стали дюже длинные.
Для оператора Write он тоже автоматически подключается. А вот для Type — нет.
Но подключается с помощью %%, а с помощью %%% еще и задействуется автотабуляция
чтобы выводимое выстраивалось в стройные колонки. (Прибамбас для вывода
значений переменных с помощью Write Set.) Для чего в недрах Фокала есть
таблица табулостопов (доступ к которой — как всегда с помощью функции FViz).
Например: For i=1,1e9; Type i; будет долго-долго вываливать на экран
числа от одного до миллиарда, при чем рассмотреть что либо не представляется
возможным. А вот: For i=1,1e9; Type %% i; — поэкранно. Но нажатие кнопки ESC
это процесс не прекратит: это надо проверить с помощью FTEll(0) и сделать
например так: For i=1,1e9; Type %% i; If(FTEll(0)),0,0; Set i=1e9
А если там написать: Type %%% "ой", "мама", "еще", "только", i
то каждый из элементов этого списка вывода будет на экране с позиции очередного
табулостопа.
Однако сейчас (5.1) у нас есть : (двоеточие) как раз и предписывающее
переход к следующему табулостопу — эффект тот же самый даже без привлечения
просмотрщика. Так что спецформат %%% в Type стал ненужен. И автор строит
хищные планы...
У этого самого просмотрщика есть счетчик выведенных им на экран строк. Ну
так обычно для каждого очередного оператора Help или Write счет ведётся с
нуля. Оператор Type его тоже сбрасывает — чисто на всякий случай. А вот со
спецформатом %%% — нет. Write %% тоже нет, а Write %%% N принудительно
устанавливает. (Уж не знаю зачем — авось пригодится...)
Спецформат вида %число в операторах ввода, а это Ask и Write с форматным
выражением, указывает "размер записи". Тоесть предписывает прочитать не
"строку" — до символа конца строки, а "запись" имеющую фиксированный (указанный
вот этим числом) размер.
* * *
(4.3) Миграция формата % в оператор Write.
Сброс содержимого А2 в канал вывода будет выглядеть так: Write % 1;
Правда при условии что А2 заведомо не пуст. Иначе потащит строку из канала
ввода. Или лучше: Write % ""; — тогда не потащит...
Однако придумано это для совершенно других целей: облегчения написания
скриптовых файлов. В том числе выдающих на экран длинные тексты, типа
всяких руководств и демонстрашек...
(Да что там греха таить: W % N "метка"; было придумано и реализовано
при попытке похвастаться красивостями (1.4) — написать демонстрационную
программку, рассказывающую о всяких FBip, FЦвет... объясняющую как их
использовать и сразу же демонстрирующую что они делают и как это выглядит.
С одной стороны тексты с объяснениями довольно длинные, а с другой — алгоритм
вовсе не тупо линейный... Там же выявилась необходимость хоть как-то управлять
просмотрщиком, который и выдаёт эти тексты на экран.)
"Командным" или "скриптовым" файлом называют программку, которая
выполняется прямо "с колёс" — по мере чтения из файла, где содержится.
Следует заметить, что "скриптовым" языком Фокал был всегда, изначально: ему
совершенно без разницы откуда поступают командные строки — с терминала или с
какого другого носителя. Терминал "выделенный" — только в плане ошибок.
Да, это куда медленнее, чем из памяти, но не всегда это важно: вот как раз в
демонстрационно-обучающих программах тексты надо выдавать на экран в темпе
восприятия пользователя...
И, кстати, а как выдавать тексты? Элементарно, с помощью оператора Type.
То есть написать текст, а потом каждую строчку заключить в "скобочки": T" и "!
Да, всего по два символа в начале и в конце строки. Но всё равно править такой
текст потом весьма неудобно. (Или надо их убрать, поредактировать и вставить
по-новой.) А нельзя ли без этого обойтись? Можно: поручим оператору Write
(который на строках (программных) как раз и специализируется) еще и копировать
строки из канала ввода в канал вывода. С некоторым преобразованием — для
удобочтитаемости. Каковое традиционно укажем "форматом" вида: %Буковка, который
придумаем потом. А пока % как и в Type — по-умолчанию, то есть один в один.
Сначала — просто указанное количество строк (или до конца файла). Например:
Write % 5
если бы вот это был бы командный файл, выдал бы вот эту и следующие 4 строки
в канал вывода (на терминал, или куда он направлен). Потому как интерпретатор
тоже читает программу построчно: вот прочитал строчку с оператором Write % 5
и указатель ввода/вывода стоит на начале следующей после него строки. Дальше
он вот эти пять строк выведет, а потом в файле будет опять командная строка:
Coment вот в данном случае комментарий...
Но каждый раз строчки подсчитывать... Как минимум чревато ошибками. Поэтому
следующая мысль: копировать до "метки" — уникального текстового фрагмента,
который заведомо не встретится в выдаваемом тексте. Укажем его оператору Write
текстовой константой и поместим в первую после конца текста строку, типа:
=========================== метка_123 =================== (для заметности).
И пусть он ищет такой фрагмент в каждой очередной строке. Если найдено — стоп.
(А строку с меткой уже не выводит.)
Это, кстати, решает еще одну важную проблему: управление порядком действий
в командном файле.
Чтобы можно было писать полноценные программы, одной линейной
последовательности действий — недостаточно. Минимальные средства управления
порядком действий это метки и переходы к ним: в том числе и к подпрограмме
(с запоминанием обратного адреса и последующим возвратом управления по нему).
Кстати, в самом Фокале именно такой минимально-необходимый набор и реализован.
Получить и запомнить адрес текущего места в файле (а вернее начала следующей,
еще пока не считанной строки) — не проблема: Set X=ftell(); (При условии,
что предшествующая операция ввода/вывода была именно с этим файлом. Если
что, для гарантии можно вставить фиктивную — типа: Oper () Псевдоним; )
Так что реализовать что возврат из подпрограммы, что цикл, который — переход
назад: Oper (X) A; или If(условие_повторения_цикла) 0,0; Oper (X) A;
(Наш командный файл скорее всего будет указан первым аргументом в командной
строке при запуске Фокала и следовательно открыт под псевдонимом А.)
Проблема — организовать переход вперёд: откуда бы нам знать смещение
интересующей нас строчки?! Единственная возможность — читать все строчки
подряд и искать в каждой из них вот эту самую "метку". Вот Write % "метка"
это и делает. (А без этого — побайтно читать файл функцией FCHr и с чем-то
сравнивать. Можно. Но сложно, громоздко, ненаглядно...) Единственное: оператор
Write %; не просто читает, а копирует. Но вот есть в операционной системе
такое полезное устройство nul где бесследно исчезает любая записанная туда
информация... Откроем его заранее, например под псевдонимом Z: O "nul" ZW
и тогда преход к метке будет: O Z; W % "метка"; O T; или сначала: O (0) A
но это если эта самая "метка" — раньше (до текущего места). При чем заведомо
раньше, а то найдёт саму вот эту строку... Просто и универсально, увы, не
получается.
А начиная с (4.4), где появились форматные выражения, возиться с
устройством nul уже не обязательно: W %! "метка"; и всё.
Далее: а КАК Write % копирует строки?
Через А2.
Да, в результате этого возникают некоторые дополнительные проблемы, чем
если бы у Write был собственный буфер. Но за-то это одновременно и средство
вывода строки из аккумулятора. И не только...
В частности, при обнаружении метки, содержащая её строка так и остаётся в
А2. И перед следующей операцией приходится его очищать: Ask %; Но и это
можно применить для пользы дела. Например:
Если текст длинный — больше размера экрана, для его вывода подключается
встроенный просмотрщик. Дающий пользователю возможность в том числе прекратить
просмотр текста. (Нажав кнопку ЕСЦ.) В результате файл, откуда его читаем, не
будет перемотан до следующей командной строки. И с этим надо что-то делать.
Узнать, что пользователь нажал этот самый эскейп (ESC), мы можем проверив
содержание односимвольного буфера клавиатуры. (Получить его: ftell(0) при
условии что предыдущая операция ввода/вывода была с терминалом или
клавиатурой.) По-идее он должен быть пуст — содержать ноль. Но если в
просмотрщике был нажат ЕСЦ, то там будет -1, что впрочем тоже означает, что
он пуст. Так что:
Ask %; Write % "_метка_"; Oper () T; If(FTEll(0)),0,0; Write %! "_метка_";
Но ведь если первый оператор Write отработал полностью, то строка, содержащая
текст "_метка_" уже в аккумуляторе. Поэтому можно куда проще:
Write % "_метка_"; Write %! "_метка_";
(Второй оператор Write или найдёт эту самую метку сразу, или таки перемотает
до неё файл.)
Резюме (типа подведём итоги): С одной стороны к (4.3) Фокал стал куда
"более скриптовым". (Это мы еще не рассматривали, как организовать стэк для
адресов возврата из подпрограмм — чтобы обеспечить их неограниченную
вложенность — как на случай, когда вся они в одном файле, так и в разных, при
чем с сохранением возможности автономного их выполнения. Впрочем, это
рассмотрено в разделе <<7>> файла справки (выдаваемой оператором Help),
непомерно в результате разросшимся...)
А с другой — обнаружились средства работы с текстовыми строками. Которых
уже достаточно для решения многих задач невычислительного характера.
* * *
пример ?
* * *
Но средства эти пока что непомерно хилые.
* * *
Прежде чем перейти к (4.4) и начать рассматривать более продвинутые
средства для борьбы с текстами, сделаем лирическое отступление — вспомним, что
мы там, в том обширном списке пропустили?
(1.2) всякие удобства, включая оператор Help, уже упоминавшийся просмотрщик
к нему (всего лишь выдающий текст поэкранно) и редактор командной строки с
прибамбасами. Включающими в себя сначала "карман", чтобы положить туда
фрагмент строки — дабы вставить в другом месте. Потом возможность захватить в
этот карман (или сразу вставить в строку) кусок текста с любого места экрана.
(Слизано с ДосНавигатора.) Потом пул (мешок) ранее введенных строк. В том
числе с возможностью сохранения его содержимого между сеансами работы (в том
самом файле _fpks.txt). Потом еще и "отладочное окно" — чтобы трассировочная
информация не затирала изображение на экране. Удобство, честно говоря,
сомнительное, а в графических режимах работает и вовсе безобразно. В то время
как использование для аналогичных целей файла протокола (того самого для
которого псевдоним Б) так и не вышло из стадии эксперимента.
Как всем этим пользоваться — см.<<1>>, для чего подать команду: Help 1
Или открыть файл foc.hlp (или какой он у текущей версии?) любым редактором
или просмотрщиком и найти там метку <<1>> (обязательно в начале строки).
Оператор Help просто выдаёт на экран разделы этого самого файла справки,
(который вполне себе текстовый), разделенные вот такими метками.
Соответственно: Help АБВГД ищет метку <>. Без аргумента Help выдаёт
краткую справку на один экран. (Самое начало файла.) А если метка не найдена,
то оглавление (список помеченных строк). Кроме <<#>> — эта часть текста в
файле справки — "закомментирована". В первом же из таких разделов — описание
организации самого файла справки.
(1.5) доработка операторов:
Что оператор If доработан для использования в "нулевой" строке, и
оператор Go с ним за компанию — см. выше. (Для Go нулевой номер строки велит
перейти к началу текущей, а для If — наоборот завершить текущую. А вот пропуск
номера строки или -1 — никуда не переходить, а передать управление следующему
после If оператору. И что из трёх выражений в операторе If вычисляется только
одно, а остальные — нет.)
Что шаг в операторе For, если он опущен, определяется автоматически, в
зависимости от того что больше — начальное или конечное значение (а не как
в (1.0) тупо устанавливается +1). Что цикл прекращается, когда значение
счетчика выйдет за конечное значение более чем на пол шага. Что опущен может
быть не только шаг, а вообще всё: For; — тогда тело цикла (остаток строки)
выполняется ровно один раз, но тоже как подпрограмма. Что тоже имеет смысл:
может служить границей распространения ситуации (см.(3)).
Что оператор Do, так же как FSBr, может иметь любое количество
дополнительных параметров, которые тоже передаются подпрограмме и становятся
Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |