{test-cfg {sort on} {rewrite off} {cfg-file {file-name "name-1" } {file-type "txt" } } {cfg-file {file-name "name-2" } {file-type "gif" } } {header-file {name "name-4" } {type "doc" } } {header-file {name "name-3" } {type "jpg" } } }
Cls-документ состоит из Cls-тегов. Каждый тег может содержать токены и/или дочерние теги. Каждый тег начинается с открывающей фигурной скобки, за которой без пробелов следует название тега. Название может состоять из любых непробельных символов.
Cls-документ может содержать комментарии, которые полностью игнорируются при разборе. Существуют два вида коментариев:
однострочный. Начинается с || и завершается в конце строки;
многострочный. Начинается с |# и завершается #|.
Многострочные комментарии не могут быть вложенными друг в друга.
При разброре многострочные комментарии заменяются на один пробельный символ. Однострочные комментации заменяются на один символ перевода строки.
Значениями тега называются все токены, указанные внутри тега без учета дочерных тегов. Различаются три типа токенов:
:tok_space (пробелы). Содержат все пробельные символы между двумя соседними токенами. Пробельными символами являются: пробел (“ ”), перевод строки (“n”), возврат каретки (“r”), горизонтальная табуляция (“t”). В отличии от C++ной версии, в ClsRuby к пробелам относятся так же и комментарии;
:tok_nonspace (не пробелы). Непрерывная последовательность символов, отличных от пробелов;
:tok_string (строка). Последовательность символов, заключенная в двойные кавычки.
Разница между :tok_nonspace и :tok_string заключается в том, что внутри строки могут содержаться пробелы. Поэтому строка должна обязательно начинаться с двойной ковычки и закрываться двойной кавычкой.
Приведенный выше пример можно представить в виде следующей разобранной последовательности токенов:
tag с именем “test-cfg”;
:tok_space со значением “nt”;
tag с именем “sort”;
:tok_space со значением “ ”;
:tok_nonspace со значением “on”;
tag с именем “rewrite”;
:tok_space со значением “ ”;
:tok_nonspace со значением “off”;
tag с именем “cfg-file”;
:tok_space со значением “ntt”;
tag с именем “file-name”;
:tok_space со значением “ ”;
:tok_string со значением “name-1”;
:tok_space со значением “ ”;
:tok_space со значением “ntt”
tag с именем “file-type”;
:tok_space со значением “ ”;
:tok_string со значением “txt”;
:tok_space со значением “ ”;
:tok_space со значением “nt”;
и т.д.
Примечание. В данной расшифровке не показаны моменты завершения разбора дочерних тегов.
Символы {, }, |, \, “ являются управляющими. Поэтому их нельзя использовать непосредственно в токенах :tok_nonspace и :tok_string. При необходимости использования этих значений необходим префиксовать их с помощью обратного слеша. Например:
\{;
\};
\|;
\\;
\“.
Для того, чтобы двойная кавычка не открывала токен типа :tok_string достаточно записать ее в виде escape-последовательности.
Примечание. Отличие ClsRuby от C++ной версии cls_2 и от оригинального языка CURL (по крайней мере от варианта языка 2001-го года) состоит в том, что внутри токенов :tok_string обязательно следует применять escape-последовательности только для символов \ и “, остальные символы внутри токена :tok_string теряют свое специальное значение. Т.е. в ClsRuby допустима, например, такая последовательность:
{some_tag "{}|" }
В то же время, для cls_2 такая последовательность должна быть заменена на:
{some_tag "\{\}\|" }
Для сохранения интероперабельности с cls_2 ClsRuby поддерживает обе формы записи, причем при форматировании в выходной поток применяется вторая форма (с принудительным escap-ингом всех специальных символов даже внутри токенов :tok_string).
Для записи любого символа можно использовать целочисленное значение кода символа, представленное в одной из систем счисления:
двоичной. Представление должно начинаться с префикса \b или \B, за которым должно следовать восемь двоичных разрядов. Например, \b01000001;
восьмеричной. Представление должно начинаться с префикса \o или \O, за которым должно следовать три восьмеричных разряда. Например, \o017;
шестнадцатиричной. Представление должно начинаться с префикса \x или \X, за которым должно следовать два шестнадцатиричных разряда. Например, \xfb.
Так же поддерживаются следующие escape-последовательности:
\n – перевод строки;
\r – возврат каретки;
\t – горизонтальная табуляция.
Во время парсинга входного Cls потока выполняется несколько стадий разбора входных символов.
На первой стадии выполняется замена всех числовых escape-последовательностей (двоичных, восьмеричных или шестнадцатиричных представлений символов). И лишь затем выполняется вторая стадия – анализ каждого разобранного входного символа и выделение токенов. Это означает, что последовательность:
{a "b"}
Может быть подана на вход парсеру как:
\x7b\x61\x20\x22\x62\x22\x7d
На третьей стадии последовательно идущие однотипные токены объединяются в один токен с аккумулированным значением. Например, если есть:
{a || На что ссылаемся. {href "reference"}}
то последовательность пробелов и комментарий после тега a будет объеденен в один токен :tok_space со значением "\n || На что ссылаемся.\n ".
При описании форматов конкретных тегов была выработана следующая нотация.
Теги описываются так, как они должны идти во входном потоке. Например:
{logging_params {use_stderr} {flush_each_line} }
Если тег нуждается в каком-то значении, то тип значения указывается в угловых скобках:
{connection_params {ip <nonspace>} {reconnect_timeout <uint>} {user <str>} {password <str>} }
В данном примере тег {ip} ожидает значение в виде одного токена :tok_nonspace. Тег {reconnect_timeout} – в виде одного токена :tok_nonspace, который должен представлять из себя беззнаковое целое число. Теги {user} и {password} ожидают по одному значению в виде токена :tok_string.
Если на какое-то значение накладывается какое-то ограничение, то это ограничение указывается после типа значения:
{connection_params {ip <nonspace>} {reconnect_timeout <uint:1..600>} {mode <str:(guest|admin|user)>} }
Т.е. {reconnect_timeout} должен получать значение в диапазоне от 1 до 600, а {mode} может принимать всего одно из значений: guest, admin или user.
Если тег ожидает какое-то более сложное значение (например, собственного формата или в виде подчиненного тега), то в угловых скобках указывается имя класса (часть имени), который способен обработать это значение. Например:
{start_at <TimeXmlSchema>}
подразумевает, что {start_at} ожидает значение, для парсинга которого потребуется помощь класса ClsRuby::TimeXmlSchemaScalarParser.
Если нужно указать необязательность какого-то тега или значения, то этот тег/значение можно заключить в квадратные скобки:
{logging_params [{use_stderr}] [{file [<str>]}] }
т.е. теги {use_stderr} и {file} могут быть опущены и это не будет восприниматься как ошибка. Более того, тег {file} может принимать необязательное значение в виде токена :tok_string.
Если какой-то тег/значение может встречаться несколько раз, то можно помечать этот тег/значение *(ноль или более раз) или +(один или более раз):
{service {ips <nonspace>+ } {message {field {name <str>} {type <nonspace>}}* }* }
т.е. тег {ips} может принимать более одного значение (но хотя бы одно значение должно быть задано обязательно), а теги {message} и {message {field}} могут вообще не указываться или указываться произвольное количество раз.
Описанная выше нотация не является обязательной к использованию – это всего лишь описание накопленного опыта. Поэтому, не стоит ее использовать, если она кажется неудобной или недостаточно точной/формальной.
# vim:ts=2:sts=2:sw=2:expandtab:ft=txt:tw=78
Generated with the Darkfish Rdoc Generator 2.