Страница произведения
Войти
Зарегистрироваться
Страница произведения

Фокал - часть 3 (пишется)


Автор:
Опубликован:
24.05.2026 — 04.07.2026
Читателей:
1
Аннотация:
Типа продолжение к "Фокал снаружи и внутри"
Предыдущая глава  
↓ Содержание ↓
  Следующая глава
 
 

Open текстовой константой! С числами — полный ажур: везде, где по смыслу нужно

число, может быть выражение произвольной сложности, которое его и вычислит.

А тут?!... Кого — как, а меня такое положение дел совершенно не устраивает!...

Но вот появились файлы, доступные на чтение и на запись, и теперь программа

сможет сама соорудить себе какой хошь оператор, в том числе вписав там в

кавычки всё что ей вздумается...

Делаем так: открываем файл (да, с фиксированным именем, но сразу и на

запись и на чтение); формируем в нём необходмую нам командную строку, или даже

несколько; перематываем этот файл в начало; переключаем на него канал ввода и

останавливаем программу оператором Quit;. Тогда интерфейсная часть

интерпретатора прочитает и выполнит (или сохранит в памяти) то, что мы вот

только что написали. Главное: последней строкой заново запустить программу на

выполнение.

Этот механизм был в Фокале всегда, изначально. Файлов для него подходящих

небыло... Да, имя файла тоже было не нужно. Однако, это не единственная

константа... Да и самомодификация — это само по себе круто: эффектно,

эффективно, смертельно опасно! Даже при предельно простой фокаловской

грамматике...

Но вот обнаружилась переменная под одну строку. При чем связанная с

механизмом ввода/вывода. Впрочем, пока еще только ввода. Да и то... Ask конешно

вводит туда строку, но сам же её и использует. Да и какие либо операции с нею

отсутствуют как класс. Но это пока...

Второй подход к снаряду.

Начался со скандала: надо было ввести нечто типа: 33А 47Б 11Ц...

Нет, число то с помощью Ask N; — это пожалуйста, а вот следующая за ним

буковка с помощью Set M=FCHR(-1); — ну никак! Оказывается, оператор Ask

захапал в свой входной буфер всю строку целиком, а функция FCHR пыталась

прочитать буковку непосредственно из канала ввода, где её уже нет...

Ну так это же неправильно!

Нехай функция FCHR берет символы непосредственно из канала ввода только

когда входной буфер оператора Ask пуст. А если нет — то из него, пока не

исчерпается. Ага. В смысле куда конь с копытом, туда и рак с клешнёй! То есть

вот щас напридумываем, как не только читать символы из оного входного буфера,

но и писать их туда — той же самое FCHr. (С разными видами параметров...)

А так же манипулировать указателем текущего места в этом буфере, до которого

символы в оном буфере уже (якобы) использованы, а после — еще нет.

И напридумывали. Правда писать в этот А2 символы получилость только в режиме

"замены символа"... Но и это хоть что-то!

Однако, осталась еще проблема ввода и вывода.

Оператор Ask конешно вводит строку в этот свой буфер (он же теперь еще и

"аккумулятор А2" — привыкаем и к вот такому названию), но во-первых только

когда полностью использовал предыдущую (или если вдруг буфер был пуст), а

во-вторых сам же её и использует.

За сим постановим, что во-первых оператор Ask с АБСОЛЮТНО ПУСТЫМ списком

ввода — только вводит. А во-вторых поручим ему-же делать этот его буфер пустым:

Ask % — перетащим сюда "формат" из оператора Type: там одиночный символ %

восстанавливает формат по-умолчанию, вот пусть и тут будет что-то подобное.

И, кстати, на будущее: Ask %число пусть вводит не до символа "перевод

строки", а указанное оным числом количество символов. Пригодится.

Осталась проблема вывода...

Миграция формата в оператор Write на предмет просмотра текстовых файлов.

А в перспективе — с преобразованием в удобочитаемый вид не очень текстовых...

(Надо так понимать — ему понравилось, охватила охота к перемене мест.)

Начиналось всё с того, что надо было выдать из командного файла на экран

довольно длинный текст, повествующий о... А, не важно о чем! Что-то типа

примитивненькой демонстрационно-обучающей системы. Текст там, естественно,

выдавался с помощью операторов Type, будучи помещен у них внутре в виде

заключенных в кавычки текстовых констант. На строку — всего по паре символов в

начале и в конце: Т".....текст....."! но всё равно набирать муторно и править

неудобно...

А давайте поручим оператору Write, и без того специализирующемуся на

сообщении нам полезной информации, еще и просмотр текстов — копирование

строк из канала ввода в канал вывода. Сколько велено, или сколько получится.

(Например до конца файла.) Один в один, или с некоторым (указанным форматом)

преобразованием — для пущей удобочитаемости...

Вообще-то это задумано было и в самом деле для просмотра содержимого

текстовых файлов. А формат — на случай если они в другой кодировке: для

преобразования текста в ДОС`овскую, с которой только и работает Фокал. Однако,

и для вывода текста из командного файла на экран — тоже годится. Но каждый раз

считать строчки — неудобно. А пусть у оператора Write % будет еще один

аргумент в виде текстовой константы — "метка". Каковую метку он теперь будет

искать в каждой копируемой строке. Как нашел — шабаш! А "метку" эту поместим в

следующую строку после выводимого текста.

Сразу же решается проблема передачи управления в скриптовом файле: есть

в операционной системе такое полезное устройство NUL, где бесследно исчезает

любое количество скопированной туда информации. (И откуда можно прочитать

неограниченное количество нулей, только это нам пока не надо.) Найти теперь

нужное нам место в файле — элементарно: скопировать всё от начала файла до

нужной нам метки на NUL. А строку с меткой на всякий случай сделать

комментарием.

Но нам то это как поможет? А вот: рассмотрим, как именно копирует Write %

строку со входа на выход? Через всё тот же входной буфер оператора Ask! Кстати,

строка с меткой в нём и останется. Потом чистить придётся с помощью Ask %

А если у нас Write % 1; и вот этот самый А2 не пуст — это и будет вывод

его содержимого. (И, кстати, А2 после этого становится пустым.)

А вот если он был пуст — тогда беда: потащит строку из канала ввода.

Поэтому лучше так: Write % ""; Обратим внимание: метка есть, но пустая.

Ввод здесь подавляется, а вывод нет, хотя по логике вещей должно быть наоборот.

Это — специально сделанное исключение...

А вот нужнО ли нам оно — нУжно ли вот так нарушать принципы? По-моему

уже нет: забегая вперёд: Write %. 0; делает в точности то же самое.

Операция . (точка) — принудительный вывод содержимого А2; при чем оператору

Write велено скопировать ноль строк, то есть — ни чтения ни записи.

В общем поступило вот такое предложение: это исключение — устранить!

Пусть работает как и положено: вводит ровно одну строку. (Потому что пустое

место есть везде, даже в пустой строке.) И ничего не выводит. (Потому что

нашло метку.) Но при этом оператор Ask; (с абсолютно пустым списком ввода)

не дублирует: во-первых Ask; удаляет завершающие строку символы ПС и ВК (они

ему совершенно без надобности), а Write % ""; — нет. (А это может быть

важно, например при работе с очень длинными строчками...) И во-вторых (опять

же забегая вперёд) после % может быть форматное выражение, которое над этой

введённой строчкою — выполняется. И вот это — тоже исключение! Потому как

обычно Write %форм_выраж "метка"; найдя в очередной строке метку, больше

ничего с нею не делает — оставляет в А2 как есть...

Итак, подведём итоги: ввод — есть, вывод — есть, с операциями правда

жиденько: посимвольное чтение/запись и манипуляция с символами как с числами.

Но плюс к этому — использование содержимого А2 там, где допустима текстовая

константа: указанием ! вместо "...". Кроме операторов Ask, Type и ф-ии FCHr,

где А2 и без того используется, а ! имеет другой смысл. (Глядишь, и

самомодефикация не понадобится...) И еще плюс к этому — текстовый "побочный

эффект" — тоже в А2. Для тех спецфункций у которых он есть. Например

FTEll("шаблон_имени_файла",,) ищущая файлы в текущем каталоге. Теперь (чуть ли

не со вчерашнего дня) включая сюда и функцию FTMP(t) и FKurs("K") — если не

вот так, а с дополнительным пустым аргументом: FTMP(t,) и FKurs("K",) а без

него — таки в канал вывода. То есть исторически сложившееся безобразие наконец

то исправлено...

Примечание: ! (восклицательный знак) подставляет не всё содержимое

аккумулятора А2, а только его якобы еще не использованную часть. И если А2

якобы пуст — пытается получить строчку из канала ввода. Пустым А2 выглядит

в том числе и когда указатель, разделяющий "уже использованную" часть строки и

"еще нет", стоит в конце А2. В этом случае, если ввод с терминала, то

содержимое А2 выдаётся сидящему за этим терминалом пользователю для

редактирования. (Забегая вперёд, там будут еще и "регистры" — ровно десять

штук, обозначаемые :0 ... :9 — вот для них честно подставляется содержимое

регистра.)

При переключении канала ввода оператором Oper, входной буфер оператора Ask

автоматически очищается. Чтобы предотвратить, пришлось добавить в псевдоним

буковку N.


* * *

Третий подход к снаряду: форматные выражения в операторе Write %выражение

плюс оператор Modify с присваиванием, который теперь можно бы назвать Move ибо

перемещает строчки между группами. Ну да нам без разницы: всё равно значима

одна только первая буква ключевого слова. Остальные — игнорируются.

Вот оператор Modify номер_строки_или_группы; мы как-то выпустили из

виду. Да, в такой форме он всего лишь скромненько позволяет редактировать

хранящиеся в памяти программные строки, запуская для каждой из них редактор

командной строки. Но позволяет редактировать не только сам текст, но и номер,

в результате чего строка в итоге может оказаться в другом месте. (Ибо удаляет

и вставляет заново.)

А что он будет делать, если его аргумент не число (номер строки) а текст?

А то же самое, что и интерфейсная часть интерпретатора! То есть либо поместит

этот свой аргумент в память, либо попытается выполнить. Понадобилось это в

комплект к пошаговому режиму, где была сделана возможность ввести и выполнить

"прямую" строку — дабы можно было в процессе отладки, наблюдения за тем, как

выполняется программа, посмотреть текущие значения переменных, или даже

заглянуть в хелп... Но исправлением и дополнением программы пусть таки

занимается тот, кому это положено — вот оператор Modify...

А за одно это резкое упрощение самомодификации: всётаки описанная выше

технология с формированием строк во внешнем файле и остановкой программы

страдает рядом недостатков... (А из А2: Mod !; — оно как-то получше.)

Следующий шаг модернизации: Mov N = A; перемещение программной строки,

в том числе с добавлением к ней: Mov N = A, B, C... где если первые из A, B,

C... — числа то это номера программных строк; а если очередной элемент — "..."

или ! (то есть строчного типа), то следующие числа рассматриваются как коды

символов. Слева от знака = (равно) в качестве N может быть как число (новый

номер строки), так и ! (восклицательный знак), и тогда результат помещается в

А2.

Таким образом появилась возможность использовать програмные строки как

переменные для хранения строчных значений. Пока что возможность — ограниченная:

хранимые там строки не должны включать символа с кодом ноль. Но это — вопрос

реализации... (Который вроде бы даже уже решен.)

А преобразование строк... Уж коли Write их копирует, то пусть сам "на

лету" что-то с ними и делает. Хотя бы по минимуму: типа вставить фрагмент

строки и/или удалить. Ну и найти, куда вставлять и что удалять, тем паче

"маркер" для этого у нас уже есть — всё тот же указатель, разделяющий уже якобы

использованную часть строки и еще нет. Но пришлось придать ему еще и

размер — чтобы указывал что нашли, а не только начало этого...

Буковки мы прибережем для грядущих встроенных форматов, а под операции

задействуем символы, которые не буква и не цифра — ровно по одной штуке на

операцию. Но некоторым нужны уточнения: например для = # ("сохранить" и

"применить") — куда именно сохранять и что применять. Так что получается уже

два символа. (Хотя, если подумать, то первый символ — операция, а следующий

после неё — вот такой специфический операнд. Неспецифические это либо число

либо строка...) Выполняются операции строго слева направо, без какого либо

старшинства, пока выражение не закончится, или до первой ошибки, когда например

попытались переместить маркер за пределы строки, или не нашли что искали.

(После чего содержимое А2 выдаётся в канал вывода, а на его место читается

новая строка из канала ввода. Если конешно вот эта была не последняя.) Да,

всё форматное выражение — "одно слово", начинающееся с символа % (процент).

И у него внутри не может быть пробела, запятой и тем более точки с запятой,

разделяющих слова, части оператора и сами операторы. В роли пробела символ _

(подчеркивание) обозначающий пустую операцию.

Основных операций — две: * / вставка и удаление. Способов перемещения

маркера тоже два — собственно перемещение на указанное числом количество

позиций, и поиск указанного строкой фрагмента. В первом случае размер маркера

становится нулевой, а во втором устанавливается по размеру найденного. А в

самом начале, когда строка еще только прочитана — маркер ставится в начало и

включает её всю. (Потому как решено, что встроенные форматы, когда они наконец

появятся, будут действовать не на всё подряд, а только на то, что под маркером.)

Два префикса + и — указывают направление перемещения. А операции ^ и $

предписывают поставить маркер в начало и в конец строки. Так: $-10*"Вася"

предписывает поставить маркер в конец, отступить на десять позиций и вставить

там слово "Вася". Если строка короче десяти символов, то операцию сдвига "-10"

выполнить не удастся и слово не будет вставлено.

(Примечание: в ранних версиях отсутствие префикса означало положительное

направление как сдвига маркера так и поиска. А вот сейчас для поиска уже нет:

без префикса наличие фрагмента, подходящего под представленный образец,

проверяется только один раз — с текущей позиции маркера. Т.е. без его сдвига.)

При перемещении, размер маркера обнуляется, но может быть установлен

принудительно операцией ~ которой нужен либо правый операнд — число, либо еще

какое либо уточнение. Например ~$ (до конца строки) ~^ (до её начала) ~. (до

метки). Эта самая "метка" — удобная штука: с помощью =. запоминает текущую

позицию маркера, а с помощью #. меняется с ним местами.

Префиксы + и — сами по себе предписывающие перемещение вперёд и назад на

одну позицию, действуют не только на следующее за ними число, но и на многие

Предыдущая глава  
↓ Содержание ↓
  Следующая глава



Иные расы и виды существ 11 списков
Ангелы (Произведений: 91)
Оборотни (Произведений: 181)
Орки, гоблины, гномы, назгулы, тролли (Произведений: 41)
Эльфы, эльфы-полукровки, дроу (Произведений: 230)
Привидения, призраки, полтергейсты, духи (Произведений: 74)
Боги, полубоги, божественные сущности (Произведений: 165)
Вампиры (Произведений: 241)
Демоны (Произведений: 265)
Драконы (Произведений: 164)
Особенная раса, вид (созданные автором) (Произведений: 122)
Редкие расы (но не авторские) (Произведений: 107)
Профессии, занятия, стили жизни 8 списков
Внутренний мир человека. Мысли и жизнь 4 списка
Миры фэнтези и фантастики: каноны, апокрифы, смешение жанров 7 списков
О взаимоотношениях 7 списков
Герои 13 списков
Земля 6 списков
Альтернативная история (Произведений: 213)
Аномальные зоны (Произведений: 73)
Городские истории (Произведений: 306)
Исторические фантазии (Произведений: 98)
Постапокалиптика (Произведений: 104)
Стилизации и этнические мотивы (Произведений: 130)
Попадалово 5 списков
Противостояние 9 списков
О чувствах 3 списка
Следующее поколение 4 списка
Детское фэнтези (Произведений: 39)
Для самых маленьких (Произведений: 34)
О животных (Произведений: 48)
Поучительные сказки, притчи (Произведений: 82)
Закрыть
Закрыть
Закрыть
↑ Вверх