Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |
(операции ** и //) временно....
* * *
Итак, еще раз про встроенные шаблоны вида %Х (где Х — одна буква) как
анализирующие так и генерирующие.
Договоримся, что любая конструкция вида %буква это обязательно встроенный
шаблон. Даже в том случае, если таковая буковка никак не задействована,
анализирующий просто ни с чем не сопоставится, а генерирующий ничего не
сгенерирует, проигнорировав доставшийся ему элемент протокола.
АНАЛИЗИРУЮЩИЕ встроенные шаблоны делятся на две группы: первые
сопоставляются с одним символом, вторые — с некоторой сложной конструкцией,
типа плавающее число (с мантисой и порядком), грамматически правильное
выражение, или хотя бы сбалансированная скобочная структура...
Из них пока реализован один только %S сопоставляющийся с текстом в
кавычках. Проблем — две: первая — как зафиксировать такую конструкцию в
протоколе и вторая, более сложная — в универсальности. Первая проблема
порождается спецоперациями ** и // позволяющими "вытащить" протокол на свет
божий и загрузить обратно, для чего он должен быть исключительно в текстовом
виде. Она вполне решаема. Вот только решения эти мне что-то не больно-то
нравятся. (Ну да: введением таки только и исключительно для протокола текстовой
константы с экранирующим символом.) Вторая заключается в том, что например мы
считаем "скобками" а что — нет? Мы то в Фокале их числим четыре вида: ([{<>}]),
а где ни будь в другом месте <> скобками не считаются. А еще кому-то
понадобится выделять фрагменты, заключенные в '/' и ''. Ну и что делать?
Получается, что встроенному шаблону, анализирующему скобочную структуру, надо
передавать параметры! Интересно, как? Хотя у нас вон там еще "постфикс" никак
не задействован... А еще есть проблема рекурсивности, которую надо
рассматривать отдельно: скобочки же могут вкладываться друг в дружку как
матрёшки на любую глубину... А если скобочка в кавычках, то скобкой она типа
не считается? Да и кавычки (не у нас!) во первых могут быть парные, а
во-вторых иметь в комплекте экранирующий символ...
Но отложим это (до следующей версии).
Пока что нас интересуют те встроенные шаблоны, которые сопоставляются с
одним символом, таким как буква, цифра, разделитель, символ псевдографики...
Но это анализирующий — сопоставляется. А парный к нему генерирующий должен
вставить нечто, получившееся из того, что получил от него через протокол.
Два крайних случая: символ, изображающий сам себя, себя же и генерирует,
игнорируя информацию из протокола. А шаблон . (точка), сопоставляющийся с
любым символом, и вставляет тоже что угодно. Один в один. При чем любую, сколь
угодно сложную конструкцию. Ага. А все остальные?
Перечислим их (честная ревизия кода, а не что я на этот счет думаю)
"объединение" (буква О может быть как русской так и латинской)
%о (строчная буква) — не различать заглавные и строчные буквы
%О (заглавная) — не различать русские и латинские
Инвертирует текущее состояние этого признака. (С учетом алгоритма
сопоставления, идейка, честно говоря сомнительная.) Следов в протоколе не
оставляет.
В генерирующем шаблоне (как это уже было написано выше) вставляет
конструкцию типа %о+ указывающую в каком этот признак состоянии.
"кодировки" (буквы — исключительно русские)
%Д %д — ДОСовсская 866
%В %в — виндовая 1251
%К %к — КОИ-8
%У %у — уникод
%И %и — ИСО 8859.5
%М %м — макинтош
Заглавная буква -> русские заглавные, строчная -> строчные. Латинские
буквы у всех перечисленных совпадают с латинскими текущей кодировки.
Планируется так же сделать:
%С %с — славянская 855
%Е %е — ебздиковская производная ДКОИ.
И вот у последней всё не так! Но пока не сделано, а там — подумаем...
(С учетом %О выделить можно любые буквы, а вот с прочими символами как?)
"типы букв" (в текущей кодировке)
%Б %B — любые заглавные
%б %b — любые строчные (но это если признак %о не установлен)
%Р %R — заглавные русские
%р %r — строчные русские
%Л %L — заглавные латинские
%л %l — строчные латинские (аналогично для признака %О)
другие классы символов (тоже в текущей кодировке)
%Ц %ц %C %c — любая цифра
%Г %г %G %g — любой символ псевдографики
%П %п %P %p — пробел или любой "слепой" символ с кодом меньше пробела
если русская (%П %п) — плюс то, чем может завершиться слово:
знаки препинания '.' ',' ':' ';' '!' '?' и конец строки
если строчная (%п или %p) — один такой символ,
а если заглавная (%П или %P) — все сколько их подряд
уникод
%U — аналог . (точки) — один символ текущего уникода
%V -//— — один правильный символ utf-8
%u %v — символ с кодом FEFF (неразрывный пробел нулевой ширины) по которому
обычно определяют тип уникода
Как уже говорилось ранее, уникод различаем "входной" и "выходной". В
данном случае входной — для анализирующего шаблона, а выходной — для
генерирующего. Устанавливаются операцией %О с числовым аргументом, но могут
быть установлены и с помощью вот этих вот встроенных шаблонов. При чем %u
определяет и устанавливает тип входного уникода только когда он
"неопределённый" — равен 0, а %v — всегда (т.е. переопределяет его заново).
На текущий момент (03.01.24/14:00) это всё что есть.
Вспомним, что генерирующему шаблону может быть передано через протокол?
— ноль символов: _
— одиночный символ: .x Аx Unnn, ! где: х — вот этот самый символ,
— группа символов: $/xxx/ &"xxx" А — буква, n — цифра
— выбор: [nn,Y] Y — любая из описанных
— последовательность: <...> здесь конструкций
— повторение: ...*...|... ... — их последовательность
В связи с тем, что в перспективе планируется реализовать возможность либо подгружать новые кодировки либо доопределять имеющиеся, но в обоих случаях занимать под новые кодировки новые буквы алфавита (примерно так же, как с псевдонимами открытых файлов) то некоторые из конструкций протокола, начинающиеся с буквы (U... и S...) возможно будут пересмотрены.
Итак, что видим? Видим деление символов на ранее упоминавшиеся классы
(буквы, цифры, псевдографика...) с выделением подклассов среди букв. (Те, что
обозначены как "кодировки" — тоже буквы, при чем русские.) Вернее
соответствующий анализирующий шаблон выделяет из входного потока символ
относящийся к этому классу и соответственно генерирующий должен вставить в
выходной поток тот же самый символ, преобразовав к своему подкассу. А если
преобразование не требуется, то там вполне можно поставить шаблон . (точка).
Ага. Вопрос только в том, что ему делать, если достанется символ
относящийся к другому классу?
— преобразовать к своему классу (а это вообще возможно?)
— вставить как есть
— не вставлять ничего
Последний случай имеет смысл если есть возможность выбора. Например в виде
конструкции [...] не парной к аналогичной конструкции анализирующего... Сейчас
то в этом случае тупо используется первый её элемент. А надо, чтобы подходящий!
Впрочем, возможен компромис: за пределами вот такой вот конструкции пусть
всё "чужое" вставляет один в один (как точка), а внутри — только "своё".
За одно разрешается и еще только наклёвывающяся проблема с перекодировками:
псевдографику (если она есть) тоже нужно перекодировать, а если нету — как-то
изобразить ("транслитерировать"). При чем существуют кодировки (не
реализованная пока ДКОИ например), где не только русские но и латинские буквы
закодированы принципиально по-другому. Да и все остальные символы тоже...
А преобразование символов между классами (например букв в цифры или в
символы псевдографики) пока что не представляется мне вомзожным.
Поэтому вот так и сделаем: за пределами конструкции [...], которой пока
что еще и нет, любой встроенный "одиночный" шаблон пусть вставляет все
"не-свои" символы один в один — как . (точка). И в роли "постфикса" — тоже.
(Которого тоже пока что нет — это после двоеточия.)
* * *
В общем будем считать, что про шаблоны пока всё.
— что там у нас еще осталось?
— а вот:
(4.9) %r и %R — близнецы братья (кто более матери-истории ценен?...)
Ну даже настоящие близнецы не совсем похожи — и тут так же. Напоминаю:
в начале был реверс — перестановка в обратном порядке: битиков в байте и самих
байтиков в указанном маркером фрагменте. (А битиков — тоже в каждом байте
фрагмента, вообще-то.) Вот это они по наследству и получили: %r работает
последовательно с каждым байтом фрагмента, а %R с ним со всем как с единым
целым. Но делать умеют почти одно и то же: свои операнды они рассматривают не
как буквы, цифры и прочие знаки препинания, а как наборы битов. (Они же
беззнаковые целые числа.)
А всё потому, что никак не получалось придумать — как одновременно указать
преобразование и между заглавными и строчными буквами, и между русскими и
латинскими, и, главное — всё это еще и для других кодировок, где тоже всё это
есть... Нет, по-отдельности — пожалуйста. А вот всё вместе... Сделать-то не
проблема, а вот как указать, что имено надо делать, да еще так, чтобы и самому
не запутаться!... Отсюда и появилась идея промежуточной кодировки, такой, чтобы
там все нужные нам преобразования производились изменением буквально одного -
двух битов. Чтобы там все буквы стояли единообразно: младшие ну например шесть
бит указывали конкретную букву, а все старшие были бы её признаками: седьмой
бит — заглавная или строчная, восьмой — русская или латинская. А если битов
больше, то и на другие алфавиты можно замахнуться...
Ага, замечательно. Но с одной стороны не все буквы — буквы: меж ними и
цифры встречаются, и прочие знаки препинания. А с другой — нужен инструмент,
чтобы эти битики признаков переворачивать. (Без инструмента и вошь не
раздавишь: ноготь нужон!) И инструмент по-возможности универсальный. То есть
не только нужные для этого побитовые операции, но и например арифметические...
Вот и.
А если учесть, что у нас есть еще и кошкой драный уникод, который в один
байт ну никак не укладывается... В общем делаем так: берём очередную буковку
(сколько бы байт она ни занимала), тащим её в тихое место, и уже там что-то с
нею делаем. А сделав — кладём назад. Или сохраняем про запас... Где? Да хоть
в переменной, хоть одном из регистров...
Образчик этого самого "тихого места" (операционный стэк) дают нам
советские программируемые микрокалькуляторы. А так же язык Форт и/или
ПостСкрипт если кто о них знает. Но там этот самый стэк — произвольной глубины,
а у калькулятора Б3-34 — ограниченной: это не компьютер и ресурсов у него в
обрез. А у нас хоть и компьютер, но инструмент-то мы делаем сугубо
вспомогательный! Так что операционный стэк — пока что те же самые четыре
ячейки. (По крайней мере пока — а потом посмотрим. Но там этого вполне хватало,
думаю, что и здесь хватит.)
Стэк, если кто забыл, это "стопка" или "кипа" — способ обращения как у
пистолетного магазина: последний засунутый — лежит сверху и взять можно только
его. Но если взял — теперь наверху засунутый перед этим... Вот только у нас не
патроны, а числа, а ячеек (пока) всего четыре: при засовывании нового,
последнее пропадает, а при вытаскивании — размножается. (Но полагаться на это
таки не следует: вдруг в будущем ячеек добавим?) Главное: каждая операция берёт
свои операнды со стэка и туда же помещает результат. Кстати, очень удобно!
Не 2 + 3 = как на обычном калькуляторе, а 2 3 + и всё. Правда между 2 и 3 надо
что-то такое, чтобы указывало что ввод одного числа кончился и начался
следующего. Там была такая кнопка со стрелкой вниз — проталкивающая верхнее
число дальше в стэк. Хотя годится и любая операция — всё что угодно, что не
циферка. У нас например _ (подчеркивание), как всегда ничего не делающее.
А удобно потому, что всякие формулы, чуть сложнее 2+2 например (5+4)/(3+2)
на обычном калькуляторе считать запаришься: промежуточные результаты придётся
на бумажку записывать, а потом вводить заново. А тут: 5 4 + 3 2 + / и всё.
Кстати, это — "обратная польская безскобочная запись" называется...
В общем у наших близнецов %r и %R всё в точности то же самое: что сделать,
передаём им в виде аргумента... Мы еще не забыли, что вообще-то всё это -
внутри форматного выражения оператора Write и выглядит: Write %_%r"операции"
То есть операцию можно передать конечно и одну, а можно вот так вот: несколько
в кавычках или скобках. Любых. Но как-то интерпретатор отреагирует на другие
виды скобок, вложенные например в Write %_%r(....); которые вполне могут быть и
не сбалансированными... Так что уже лучше в кавычках.
Итак, у обоих — операционный стэк из четырёх ячеек и одни и те же операции:
& | ^ ~ побитовые: И, ИЛИ, исключающее ИЛИ, инверсия; + — * / арифметические.
Деление — целочисленное: даёт два числа — частное (сверху) и остаток (под ним).
Чтобы до него добраться (да и вообще) — операции реогранизации вершины стэка:
[ дублирование верхнего числа, ] обратная к ней — удаление его нафиг. А так же
: обмен пары и @ обмен всех четырёх — засовывание самого верхнего под низ.
Стэк у нас таки не стопка как в ПостСкрипте, а магазин фиксированной ёмкости.
(Можно было конечно и стопкой сделать, в том числе неограниченного размера.
Но тогда была бы возможна ситуация, когда на стэке ничего нет, а мы пытаемся
выполнить с этим какую-то операцию — пришлось бы как-то на это реагировать...)
Главное отличие: операции , . ; (запятая, точка, точка с запятой) — взять
очередной i-ый байт из обрабатываемой последовательности, положить его обратно
(удалив со стэка), а так же обменять их местами. (Кстати, операция 'i' сообщает
нам индекс текущей позиции, а 'l' — сколько еще осталось.) Договорились, что
если ,, или даже ,,, то значит надо взять за раз два и три байта. Или если ..
и ... то соответственно положить. А если взяли один, а положили три... Да,
тоже можно: обрабатываемый фрагмент соответственно в этом месте раздвигается.
Но уж коли мы взяли три, то i на эти три байта и продвинется... (А надо взять
еще раз, но один. И за ненадобностью выкинуть со стэка уже упоминавшейся
операцией ']'.)
Для "старшего братца" %R, который берет всю эту входную последовательность
целиком, все эти детские игры с многоточиями разумеется совершенно никчему.
Казалось бы, этим можно и ограничиться... Ну добавив еще обращения к
переменным (=X #X, где X — любая буква) и регистрам (=N #N, где N — цифра),
и еще вот эти самые перекодировки — в виде обозначающих кодировку буковок:
Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |