У меня есть конвертер bbcode -> html, который реагирует на событие изменения в текстовом поле. В настоящее время это делается с помощью ряда регулярных выражений, и есть ряд патологических случаев. Я всегда хотел поточить карандаш в этой грамматике, но не хотел влезать в бритье яка. Но... недавно я узнал о pegjs, который кажется довольно полной реализацией генерации синтаксического анализатора PEG. У меня есть большая часть грамматики, но теперь я задаюсь вопросом, является ли это подходящим использованием полнофункционального синтаксического анализатора.
Мои конкретные вопросы:
Поскольку мое приложение основано на переводе того, что я могу, в HTML и оставлении остального в виде необработанного текста, имеет ли смысл реализация bbcode с использованием синтаксического анализатора, который может дать сбой из-за синтаксической ошибки? Например:
[url=/foo/bar]click me![/url]
, безусловно, будет успешным, как только будет введена закрывающая скобка закрывающего тега. Но что пользователь увидит в это время? С регулярным выражением я могу просто игнорировать несоответствующие вещи и рассматривать их как обычный текст для целей предварительного просмотра. С формальной грамматикой я не знаю, возможно ли это, потому что я полагаюсь на создание HTML из дерева синтаксического анализа, а синтаксический анализ не удается... что?Я не понимаю, где преобразования должны быть сделаны. В формальном синтаксическом анализаторе на основе lex/yacc у меня были бы заголовочные файлы и символы, обозначающие тип узла. В pegjs я получаю вложенные массивы с текстом узла. Я могу сгенерировать переведенный код как действие парсера, сгенерированного pegjs, но это похоже на запах кода, чтобы объединить парсер и эмиттер. Однако, если я вызову
PEG.parse.parse()
, я верну что-то вроде этого:
[
[
"[",
"img",
"",
[
"/",
"f",
"o",
"o",
"/",
"b",
"a",
"r"
],
"",
"]"
],
[
"[/",
"img",
"]"
]
]
учитывая грамматику вроде:
document
= (open_tag / close_tag / new_line / text)*
open_tag
= ("[" tag_name "="? tag_data? tag_attributes? "]")
close_tag
= ("[/" tag_name "]")
text
= non_tag+
non_tag
= [\n\[\]]
new_line
= ("\r\n" / "\n")
Я, конечно, сокращаю грамматику, но вы поняли. Так что, если вы заметили, в массиве массивов нет контекстной информации, которая подсказывает мне, какой у меня узел, и мне остается снова сравнивать строки, даже если синтаксический анализатор уже сделал это. сделал это. Я полагаю, что можно определить обратные вызовы и использовать действия для их запуска во время синтаксического анализа, но в Интернете мало информации о том, как это можно сделать.
Я лаю не на то дерево? Должен ли я вернуться к сканированию регулярных выражений и забыть о синтаксическом анализе?
Спасибо