Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |
язык Алгол-60. Где знаков математических операций — куча, а вот вопросительный
знак никак не используется. Вот нашелся же безголовый исполнительный кАзёл,
делающий всё тупо по ТЗ! А кто это ТЗ писал — он то куда смотрел, чем думал?...
— а про ёлку-то ты не забыл, боярин дубовый?
— когда жёлудь спелый...
Нет, так не годится! Пробуем по-новой:
В UNIX`овском шаблоне, кстати, есть еще и конструкция [...] которую не
грех и позаимствовать. И если считать, что весь шаблон это последовательность
"элементарных", где например любая буква изображает только сама себя,
конструкция %Б — любую букву (но только одну), %Ц — любую цифру, а точка вообще
любой символ, то в <...> должны сопоставиться все элементы, а в [...] — только
один. Любой. А так как сами <...> и [...] тоже элементарные, то ничто не мешает
им вкладываться друг в дружку как матрёшки... Кстати, префиксы повторения
действуют только в <...> потому что это — последовательность. А [...] — выбор.
И в результате, кстати, вырабатывает одно единственное число — номер выбранного
элемента. В то время как <...> для каждого своего элемента пишет в протокол...
— они что, еще и, как милиция, протоколы составляют?
— да! А иначе как же шаблон "генерирующий" сможет чего ни будь сгенерировать
по обращику того, с чем предшествующий ему анализирующий сопоставился?
Вот — по этому самому протоколу...
Мы еще не забыли, что строчное значение участвует у нас в двух операциях:
поиск и вставка? Вот когда поиск — шаблон анализирующий, а когда вставка -
генерирующий. Но это мы таки забегаем вперёд: на уровне (4.6) (и долгое время)
были одни только анализирующие. Как передать от них информацию генерирующим
было непонятно — книжку, чтобы осмыслить это, писать пришлось! (По принципу:
не понял сам — объясни другому...) Но оказывается всё просто: шаблон, вспрочем
как и самое обычное арифметическое выражение — это ведь фактически дерево.
А их запись в программе — развёртка этого дерева в линию (одномерную
последовательность). Ну так процесс сопоставления тоже порождает дерево, хотя и
несколько другое. И можно сразу получить его линейную развёртку — прямо в
процессе сопоставления. А не возиться ни с какими списками, а потом еще
городить средства их обработки, порождая нечто LISP`о-подобное... Просто надо
писать её по стековому принципу: каждый элемент последовательности прежде чем
вписать себя в протокол, должен запомнить положение указателя его текущего
места. И если ему не удалось сопоставиться — восстановить его как было.
Впрочем, каждому даже и не надо, а надо тому, кто его вызывает — тому фрагменту
программы, который интерпретирует выбирающую конструкцию [...] а так же
префиксы повторения...
Впрочем, ближе к делу! То есть к грамматике.
Напомним, что шаблон это в некотором смысле аналог "....". Анализирующий
шаблон некоторым образом "сопоставляется" с символами строки в А2 от того
места, куда указывает маркер. Если не сопоставился — ошибка. (И тогда
выполнение форматного выражения завершается. Если конешно нету постфикса '&',
'' или '?'.) Но при наличии префикса '+' или '-' маркер сдвигается и попытка
сопоставления предпринимается по-новой. В чём собственно и заключается
операция поиска.
Элементами шаблона являются следующие конструкции:
— '_' (подчеркивание) — всегда успешно сопоставляется с нулём символов
— '.' (точка) — успешно сопоставляется с любым символом — ровно адын штука
— '^' и '$' — сопоставляются с началом и концом строки. Если поставить их в
середине шаблона, то он гарантированно не сопоставится ни с чем
— '!' — сопоставляется с СИМВОЛОМ перехода на следующую строку. Таковой может
найтись и посередь строки в А2, хотя конешно обычно стоит в её конце.
Потому что механизм ввода/вывода именно по нему и завершает ввод. (А вот
редактор командной строки при вводе с терминала его вообще не добавляет.)
— любая буква и любая цифра изображает сама себя (но с учетом 'o' и 'O')
— конструкция, состоящая из символа '%' и любого значка, не являющегося
буквой или цифрой, изображает вот этот значёк. (В том числе %% — сам
символ '%'.)
— конструкция, состоящая из символа '%' и буквы — один из встроенных шаблонов
— конструкция, состоящая из символа '%' и цифры — то же самое, что и <....>
если бы содержимое угловых скобок заранее поместили в указанный цифрой
регистр.
— конструкция <....> сопоставляется, когда сопоставились все заключенные в
ней элементы, а конструкция [....] — когда хотя бы один (следующие после
сопоставившегося игнорируются).
— конструкция (....) тоже вполне допустима, но игнорируется.
Главное: внутри <....> перед любой из таких элементарных конструкций может
стоять префикс повторения. А после — постфикс (через двоеточие). Каковых
постфиксов до сих пор никаких не реализовано. (И даже оное двоеточие пока не
отрабатывается.) А префиксов — очень даже: это уже упоминавшиеся '*', '?', '+'
и конструкция {....}. А между ними и повторяемым элементом может так же быть
еще и '-', предписывающий использовать "ленивый" (а не "жадный") алгоритм.
А вот внутри [....] никаких префиксов нет: '*', '?' и '+' — самые обычные
символы. А конструкция {....} изображает символ с кодом, вычисленным
содержащимся в ней выражением. Но за-то в [....] есть "диапазон" и "отрицание".
Уже упоминавшийся диапазон образуется из двух не-групповых (т.е. изображающих
один символ с конкретным кодом) конструкций. А вот "отрицание" это символ ~
(тильда) сразу после открывающей скобки. (Что тоже, кстати, слизано из UNIX`а.)
Тогда [~...] становится "негативным": сопоставляется с нулём символов в
случае, если не сопоставился ни один из его компонентов.
Вот собственно и вся грамматика.
У "генерирующего" шаблона она такая же в точности. Вот только его смысл...
(4.7) Смысл его (генерирующего шаблона) в том, что он, будучи правым
операндом операции вставки '*', должен сформировать для неё фрагмент строки,
руководствуясь "протоколом", который ему оставил предшествующий анализирующий.
Нет, если весь он состоит из символов, изображающих сами себя, то и никакой
протокол ему не понадобится. (Но чем он тогда отличается от константы в
обычных кавычках?!) Протоколом руководствуется прежде всего префикс повторения:
он должен повторить свою конструкцию ровно столько раз, сколько и парный к
нему в анализирующем. Во-вторых — конструкция [....] — она должна выбрать тот
же вариант, что и. В третьих — '.' (точка) — она должна вставить тот же самый
код, что и. Ну и некоторые встроенные шаблоны, о которых мы что-то совсем
забыли...
(Ничего, скоро вспомним!)
По идее анализирующий и генерирующий шаблоны должны быть конгруэнтны. Чтобы
каждой из конструкций досталось то, что записала парная к ней — такая же.
Должны, да не обязаны! Поэтому смотрим что пишет в протокол какая из
конструкций и что потребляет. (Впринципе протокол этот — почти текстовый.
И его вполне можно вытащить и посмотреть, вставив спецоперацией **. А парная к
ней спецоперация // делает протоколом удаляемый ею фрагмент под маркером. Но
обе — чисто для отладки и не уверен что будут сохранены в следующих версиях.)
— "последовательность" <...> (в том числе и весь шаблон целиком) фиксируется в
в протоколе в виде пары скобок < >, между которыми — её элементы.
И "потребляет" такую же последовательность, последовательно предлагая её
элементы каждому из своих членов. (А буде кому недостанется...) А получив
только один элемент — предлагает его каждому из своих членов.
— любой префикс повторения "выгораживает" участок внутри последовательности,
начало которого отмечается символом '*' а конец — '|', и между ними — элементы,
с которыми сопоставилась повторяемая им конструкция. В том числе возможно что
и ни одного. "Потребляет" последовательность до '|' или до '>' (если конешно у
него там не указано предельное значение), предлагая тому что повторяет,
следующий очередной элемент на каждой итерации.
— "перечисление" [...] отображается парой скобок [ ], в которых число (номер
сопоставившегося элемента), запятая и то, что с ним сопоставилось. "Потребляет"
такую же конструкцию. И только тогда выбирает указанный в ней элемент (а не
первый). А вот если это число больше, чем у него элементов... (Даже и не знаю:
пока будем считать, что не вставит ничего.)
= а вот если перечислению в генерирующем шаблоне достался не вышеописанный
элемент протокола, а что-то другое, вот тут и начинается самое интересное.
Но пока что не реализованное. То есть это и должен быть настоящий выбор: к
доставшемуся конструкции [...] элементу протокола последовательно применяются
все её компоненты, пока очередной не подойдёт. Однако, подошедший элемент
должен иметь возможность сгенерить не только то, что он описывает, но и что-то
другое. И вот тут нам бы как раз и пригодились обещанные постфиксы, до сих пор
не реализованные...
Постфиксы были бы полезны и для анализирующего шаблона. Например шаблон
типа: :@ч описывающий число с плавающей запятой,
запишет в протокол не точную его конструкцию, а абстрактный факт "@ч",
указывающий что имело место быть число. (Шаг к синтаксическому разбору?)
А в генерирующем, обнаружив эту абстракцию, заменить её на что-то конкретное...
— элемент шаблона, успешно сопоставившийся с нулём символов отображается '_'.
Это и негативное перечисление [~...] у которого не сопоставился ни один из его
элементов, и пустой шаблон '_', и '^', '$' сопоставляющиеся с началом и концом
строки. Предложенный ему элемент протокола "потребляет" но никак не использует.
— элемент шаблона, сопоставившийся с одиночным символом 'Х' отображается в
протоколе как '.Х' — это может быть и символ, изображающий сам себя и '.'
(точка) обозначающая любой символ. Символ, изображающий сам себя, предложенный
ему элемент протокола никак не использует, а вот '.' (точка), которая сама-то
сопоставляется хотя и с любым символом, но только с одним — вставляет что
угодно. В том числе получив '<' — всё вплоть до закрывающей скобки '>'.
— встроенный шаблон вида %Б сопоставившийся с одиночным символом 'Х'
отображается в протоколе как 'БХ'. Шаблон '.' (точка), получивший это,
символ Х и вставит. А вот если это достанется другому шаблону на вроде %В,
то вот тут как раз и начинается самое интересное. Потому что все эти %Б %В %Г
%Д... описывают некие группы символов и по сути являются аналогом конструкции
[...]. Следовательно: если символ попал в диапазон, описанный как %Б, то %В
должен вставить символ из своего диапазона, но с тем же номером.
Ну и что же, спрашивается, они все значат?
На текущий момент %Б это любая заглавная буква, а %б — строчная.
Соответственно %Р %р — русские буквы, а %Л и %л — латинские. В текущей 866-й
кодировке и с учетом предшествующей шаблону операции 'o' или 'O'. (Русскими
буквами считаются так же четыре дополнительные: Ё, Э-не_оборотное, И-латинское
с двумя точками и У с надчеркиванием.) Было так-же задумано, что латинские
буквы %B %R %L обозначают любую букву соответствующего типа. Однако сейчас, с
учетом 'o' и 'O' это по-видимому уже не нужно...
%Ц %ц %C %c — одна цифра; %Г %г %G %g — символ псевдографики; %П %п %P %p
пробел, а так же любой "слепой" символ с кодом меньше чем у пробела, но %П %п
еще и знаки препинания . , : ; ! ? тоже указывающие конец слова. При чем %p %п
ровно один символ, а %П %P — вся последовательность идущих подряд символов этой
категории.
%V %v — одно правильное число, закодированное в стиле utf-8 без попыток
распознать код FEFF даже если тип входного уникода — 0. %U — один любой символ
уникода (указанного типа — вот как раз "с попытками", если он ноль) %u — один
единственный код FEFF "неразрывный пробел нулевой ширины" по которому все
всегда тип уникода и определяют. В протокол пишется как Uчисло.
Вот надо честно сказть, что сочинение вот таких вот описаний (а это уже далеко не первое) — это фактически ревизия сделанного — так же, как написание шпаргалки при подготовке к экзамену. Вот написав это, сейчас я вдруг увидел, что заглавные %Ц и %Г тоже надо бы как и %П сделать чтобы не с одним символом сопоставлялись, а с последовательностью этой категории; %Ч соответственно сделать правильное число со знаком, мантисой, порядком, десятичной точкой и возможно предшествующими пробелами. Уж коли мы заикнулись про постфиксы — сделать чтобы после двоеточия конструкция хотя бы игнорировалась; вспомнить про '#' и '='... Для #N (где N — цифра) сделать что в регистре N константа (а не шаблон как %N), а #X — просто код, указанный числом в соответствующей переменной. Впрочем, у нас в [...] для этого есть заключенное в {} выражение. Ну тогда пусть значение уникода. Соответственно, =N — помещение в регистр того, что уже сопоставилось, а после двоеточия — того, с чем сопоставился данный конкретный элемент. Соответственно =Х после двоеточия — размер этого элемента, а просто так — текущее смещение относительно начала строки в А2... А еще возможность присваивания в конструкции {...} Но не всё сразу — пока что только запишем всё это в "недоделки".
Уже упоминавшиеся (в связи с перекодировками) %В %в, %К %к, %И %и, %У %у
обозначают русские буквы в соответствующей кодировке — заглавные и строчные.
(%С %с, %Е %е, %М %м — тоже, но пока не реализованы.) Потому как латинские
у всех у них одни и те же. (Кроме "Е", где вообще черт знает что. Но там можно
будет использовать 'O'.)
Осталось еще %S %s — единственная (пока) сложная конструкция:
— %s сопоставляется со строчной константой в кавычках, а
— %S со сбалансированной скобочной структурой. Где, кстати, скобки, попавшие
внутрь кавычек "погоды не портят". Отображаются в протоколе как $/....../
где ..... — любые символы, / / — тоже любые символы, которые среди них не
встречаются. Но все они должны быть "печатные". При наличии "слепых": &"....."
где, как и в Си-шной текстовой константе используется экранирующий символ .
Отличие только в том что числа NNN, только десятичные (или восьмеричные, если
начинаются с нуля) и могут отделяются от следующих символов запятой. (Если там
дальше тоже запятая, или цифры — то обязательно.)
Остальные сложные вещи, такие как правильное фокаловское выражение,
правильное форматное выражение и правильный шаблон — это на будущее...
А по-поводу нарушения фокаловских принципов конструкцией &"..." протокола...
Подумать таки надо. Но внутреннее представление всё равно другое а это
Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |