Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |
Уже читает из буфера (и вот как раз ровно один символ) функция FCHR. Есть мнение поручить ей и всё остальное.
4.2.1 Функция FCHR (с аргументом -1) берет из оного буфера код очередного символа и сдвигает указатель "текущего места", отделяющий уже использованную часть строки от еще нет... Но символ всё равно остаётся в буфере, и ничего не стоит "возвратить" его назад, просто сдвинув указатель обратно.
Это делает сама же FCHR() но без аргументов. И за одно сообщает — сколько там в буфере еще осталось не введенных символов.
Она же: FCHR( ,N) — двигает не на одну, а сразу на N позиций. В том числе и в другую сторону, если N — отрицательное. Или никуда, если 0. Только сообщает.
Она же: FCHR( , ) — измеряет буфер в другую сторону: сообщает сколько в нём "уже введенных" символов.
* * *
теперь для полного комплекта нам недостаёт средства поместить любой произвольный код в текущее место текстового буфера.
4.2.2 Хотим получить в виде числа код символа "а". (Нет, ну ей богу — надоело постоянно заглядывать в таблицу кодов символов!) Это сделает FCHR("а").
А если в текстовой константе их будет два: FCHR("аб"), то второй получим следующий раз. Для чего поместим его... А вот в текущее место буфера и поместим! Прямо поверх того, что там уже было. И все следующие аргументы функции, если они есть — тоже.
* * *
теперь не хватает только возможности вывести то, что получилось...
4.3 Если мы затеяли написать что ни будь демонстрационно-обучающее, выводящие на экран длинные тексты, то никакой памяти хранить всё это не напасешься! Однако, здесь мы никуда не спешим: делать что либо всё равно надо в темпе восприятия пользователя. Потому подобное есть смысл выполнять прямо из файла, где эта программа хранится. Вон в первых ЭВМ вообще памяти для программ не было (её и для данных то не хватало), вводили снаружи (типа с перфоленты), и ничего... И мы тоже не баре.
В общем это и будет "скриптовый" (он же "командный") файл. Ничего сложного: Строки из файла выполняются в точности так же как и введенные с терминала. С линейным алгоритмом вообще никаких проблем нет. Разветвленный конешно требует меток и операторов перехода к ним, но в этом качестве прекрасно сойдут файловые адреса (положение указателя чтения/записи файла) которые можно получить с помощью FTEll, хранить в переменных (т.к. это просто числа) и применять для позиционирования с помощью оператора Oper. Это и будет аналог оператора перехода. В хелпе про всё про это — целый раздел (под N 7).
Однако, применительно к выводу текста есть проблема: его придётся выводить в точности так же, как и программе загруженной в память: каждую строку заключить в кавычки, поместить получившуюся текстовую константу в оператор Type и еще снабдить символом ! для перехода на следующую строку.
Хотя казалось бы — чего проще: текст хранить в файле "как есть" (так его и набирать и потом править куда удобней) и просто копировать в канал вывода нужное количество очередных строчек. Ну может быть с некоторым преобразованием. Или же просто "как есть". (А дальше будут опять команды.)
Ан, в Фокале нету подходящего средства!
Ну не побайтно же копировать в цикле, с помощью FCHr! (Хотя можно, и вполне работает.)
Это дело решили поручить оператору Write, указав преобразование в виде конструкции "формат". (Который прямо на глазах становится всё более и более таинственным.) Или без преобразования, если формат пустой — состоит из одного только символа %.
В общем теперь W % N выдаст в канал вывода N строк. Прочитав их из канала ввода через тот же самый входной буфер оператора Ask.
Но вот если буфер не пуст, а вывести велено ровно одну строку, то единственное, что сделает W % 1 — выдаст содержимое буфера в канал вывода.
* * *
ага, вот и вожделенный вывод, которого нам так не хватало.
4.3.1 Но практика показала, что так оно конешно лучше, чем каждую строку в виде текстовой константы в отдельный оператор Type. Но подсчитывать строчки — тоже не фонтан. И поэтому для оператора Write с форматом была придумана "метка".
Это параметр в виде текстовой константы, которую W % "..." ищет внутри каждой введенной в буфер строки, и обнаружив — прекращает работу. Строка остаётся в буфере, а количество скопированных строк — в числовом аккумуляторе. (Откуда его не трудно достать функцией FSUBr().) Если указаны и метка и количество — то что сработает раньше. Если ни то ни другое — то до конца файла. Будет ошибка. Или, если ввод с терминала — пока пользователь не нажмет ESC. Тогда ошибки не будет. Если указано отрицательное количество строк — то тоже до конца файла, но ошибки не будет.
5.4.7 А сам оператор Write (без формата) тоже немножко доопределён — чтобы он выдавал не только программные строки, но и другие сведения о внутреннем состоянии интерпретатора (например значения переменных). Причем в форме, пригодной для последующего обратного ввода. Что именно — указывается вторым ключевым словом:
— А — как и раньше — вся программа и перед нею заголовок (кто и когда вывел).
— S — результат работы оператора Set (т.е. значения переменных)
— O — результат работы оператора Open (т.е. псевдонимы открытых файлов)
— B — результат работы оператора Break (т.е. реакция на события)
— D — результат работы оператора Do (т.е. состояние стека возвратов)
Последнее имеет смысл применять либо в какой то из подпрограмм, либо в пошаговом режиме встроенного отладчика.
Еще есть ключевое слово П (от слова "пул"), заставляющее поместить в этот самый пул содержимое строчного аккумулятора. Так как "пул" это мешок, только по нерусски, то и ключевое слово М делает то же самое.
Аргумент в виде числа — как и раньше указывает строку или группу строк.
Аргумент в виде текстовой константы — указывает имя переменной. В результате чего оператор выдаёт значения не всех переменных, как с ключевым словом Set, которых может быть очень много, а только с указанным именем.
5.4.8 Точно так же сделано и в операторе Eraze: теперь он тоже может удалить не только все переменные разом (когда без параметров), но и одну конкретную, указанную текстовой константой.
С ключевым словом Пул или Мешок оператор очищает этот самый пул редактора,
С ключевым словом Break — обнуляет счетчики все отслеживаемых внешних событий.
С ключевым словом Ales оператор удаляет всё что можно: кроме переменных и программных строк, еще и все псевдонимы открытых файлов. Но кроме тех, на которые указывают каналы ввода и вывода.
4.4 А теперь к "...." добавим еще и ! указывающий на строчный аккумулятор. Чтобы строку из него можно было использовать везде, где и строчную константу. Кроме операторов Ask и Type, где восклицательный знак уже испокон веку используется для обозначения конца строки и перехода на следующую.
5.4.9 В том числе в операторе !, который в этом случае будет выглядеть как !! Как и в UNIX`е, это обращение к операционной системе. Ей в качестве командной строки передаётся вся строка после восклицательного знака. (А теперь вот — и из аккумулятора.)
Потому что например создать новый файл Фокал может, а удалить после того как попользовался и он стал не нужен — нет. И переместить/переименовать — тоже нет. Но всё это можно сделать командами операционной системы.
Этак можно и утилиту какую запустить (Если ей конешно памяти хватит.) Текстовый редактор например. Или аналог Нортон-командера — по каталогам полазить. (А редактор в нём встроенный. И просмотрщик...) Сам Нортон или например Дос-навигатор — вряд-ли, а Волков-командер — как с куста!
* * *
В результате, теперь можно сказать, что Фокал немножко научился работать и со строками. Правда хранить их по-прежнему приходится снаружи — в виде файлов...
Потому что совсем немножко он и раньше умел: посимвольно, таская их функцией FCHR и сохраняя как числа в элементах массива. (Что конешно же стрельба из пушек по воробьям.)
Однако, и сейчас, если мы например организуем диалог с пользователем, для исправления некой даты/времени, то прочитать набранную пользователем строку и преобразовать её обратно в число — запросто. А вот чтобы использовать в качестве начального значения то, что выдаёт FTMP — временный файл понадобится. (Который потом еще и удалять придётся.) Потому что FTMP(t) выдаёт текстовый результат прямо в канал вывода.
Да и для самомодификации программы — тоже временный файл. Конешно сейчас это уже не очень нужно. Но всё равно остались места, где только и исключительно константы. (Вон этот самый таинственный "формат".) А вдруг понадобится сделать его таким, как вычислила программа...
6.3 Самомодификация программы — это круто! Эффектно, эффективно и чрезвычайно опасно. Ну прямо цирковой номер: выполняющаяся программа на ходу переписывает и исправляет сама себя! Да, в Фокале такая возможность была всегда. (В отличии от...) Хотя и ограниченная. Но с появлением доступа к файлам, в которые можно сначала записать, а потом перемотав в начало прочитать написанное...
Ну так берем такой временный файл, формируем в нём какие нам надо программные строки, перематываем в начало, переключаем на него канал ввода и останавливаем выполнение программы оператором Quit. Управление получает интерфейсная часть интерпретатора; она читает и помещает в память всё то, что мы вот только сейчас написали. Главное — не забыть в конец добавить команду, которая бы запустила программу заново с нужного нам места.
* * *
А нельзя ли как-то без временного файла обойтись? Например немножко доопределив оператор Modify, каковой как раз программные строчки исправляет...
Можно.
5.4.10 Оператор Modify.
Предназначен для того, чтобы пользователь мог исправлять программные строки, а не вводить их заново. Реализован простейшим образом: всего лишь для каждой из строк, ну например указанной ему группы, по очереди запускает редактор.
Сначала он позволял исправлять только текст строки; потом и её номер — чтобы можно было например переместить строку в другую группу. Но это же получается что теперь он (частично) выполняет функции интерфейсной части интерпретатора. Вот пусть и...
Было решено:
— во-первых разрешить в Modify параметр в виде текстовой константы. (И "..." и ! разумеется.) Чтобы делал с этой строкой в точности то же самое, что и интерфейсная часть: если там в начале есть корректный номер — помещал в память, а если нет — сразу выполнял. И всё это без манипуляций с файлами и остановки программы. (А то локальные объекты теряются.)
— во-вторых ввести форму "с присваиванием". Якобы для перемещения программных строк из одной группы в другую: Mоve N = M; (где N и M — числовые выражения.) В результате чего строка с номером M перемещается в группу N, или просто получает другой номер.
— и наконец в третьих разрешить в форме с присваиванием использовать строчные константы. (В левой части присваивания — только !.) Что даёт возможность перемещать программные строки в аккумулятор и обратно.
* * *
Обратим внимание, что на грамматическую правильность помещаемые в память программные строки никто никогда не проверяет. (Проверяет "исполнительная" часть интерпретатора — в по ходу выполнения.) Так что храниться там может абсолютно что угодно. Только на выполнение не запускай!
### К сожалению не всё что угодно: только "печатные" символы (а не произвольный код), потому что конец строки определяется по символу с кодом 0. Поэтому же в операторах Ask и Write не реализован для чтения из файлов формат %N — чтение не построчно, а порциями по N байт.
И кроме того — ограничение на длину строки. (По размеру текстового буфера, в данной версии — 122 символа.)
* * *
Это же аналог переменных для строчных значений получается!
Обратим внимание: для хранения числа используются "переменная", которая идентифицируется строкой (хотя пока это и только первые её два символа), а вот аналог переменной для хранения строки идентифицируется числом. Тоже ограниченным до двух (ан нет, уже четырех) десятичных цифр до и после запятой.
* * *
Ага-ага: хранить, вводить/выводить и применять строчные значения для специфических целей (например пропикать азбукой морзе с помощью FBIp) научились. А вот средства анализа и преобразования — крайне слабые.
Однако, еще не вечер. Что там у нас с форматом в операторе W, якобы сложным и таинственным?
4.5 Формат в операторе Write (делающий из него совершенно другой оператор!) до сей поры представлялся одним только символом % указывающим, что строки копируются как есть.
Но было задумано что преобразования указываются буквами. (Например %К преобразует русские буквы из кодировки КОИ-8 в текущую — ДОС`овскую, известную как cp866, а %W соответственно из виндовой cp1251.) А %Число так же как и в Ask ограничивает размер поля ввода — это если для терминала. А для файла — чтобы указывало размер порции, вводимой за раз.
Ни то ни другое до сих пор не реализовано. А реализованы некие "операции". Операции типа удалить, вставить, передвинуть маркер... Каждая, как и полагается, один символ. Вот эти самые буковки, если и когда будут — тоже будут такими операциями.
Выполняются эти операции без какого либо старшинства (такого, как у арифметических операций в фокаловских выражениях) — просто слева направо. И "левым операндом" каждой является вот этот самый регистр-аккумулятор — содержащийся в нём текст и/или вышеупомянутый маркер, указывающий его фрагмент. Но некоторые могут иметь так же и правый операнд. Типа "число" или "строка". В простейшем случае это числовая константа в виде последовательности циферок, или строчная константа в виде любых символов, заключенных в кавычки.
4.5.1 "Маркером" таки назовём этот самый указатель, отделяющий уже использованную часть входного буфера оператора Ask, от еще нет. Он указывает начало "фрагмента" и дополнен его размером. После сдвига маркера этот размер равен нулю. А после поиска фрагмента — равен размеру найденного. Но операцией ~ этот размер можно установить искусственно. Или изменить.
Маркер можно поставить в начало и в конец строки (операциями ^ и $), сдвинуть на указанное количество позиций или переместить путем поиска. Операцией поиска служит "строка", сама же и указывающая что искать, если не является чьим-то операндом. А так же "шаблон" — конструкция, заключенная в угловые скобки <...>, где некоторые символы выполняют служебные функции. (В отличии от строчной константы, в которой каждый символ изображает сам себя.) Операцией сдвига служит "число" — тоже если не является чьим-то операндом.
Как сдвиг маркера так и поиск могут быть как вперёд (к концу строки), так и назад — к началу. Это указывают префиксы + и -. Они именно префиксы, действующие на различные операции. (Хотя и родились из идеи, что числу, указывающему на сколько сдвинуть маркер, нужен знак — направление.)
Сами + и -, когда не префиксы (например перед ^ $ или _) указывают сдвиг вперёд и назад на одну позицию.
Например команда ~N устанавливает размер фрагмента ровно N символов независимо от того, какой он был до этого. А вот +~N и -~N увеличивают его на N символов в сторону конца и соответственно начала строчки. Уменьшают только если само число N отрицательное. Чего можно добиться, написав {-N} — вот тут минус это действительно знак. А само N в фигурных скобках может быть полноценным фокаловским выражением.
Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |