Парсер против лексера и XML
Сейчас я читаю об архитектуре компиляторов и синтаксических анализаторов и меня интересует одна вещь... Когда у вас есть XML, XHTML, HTML или любой язык на основе SGML, какова будет роль лексера здесь и какие будут токены?
Я читал, что токены похожи на слова, подготовленные лексером для анализа. Хотя у меня нет проблем с поиском токенов для языков C, C++, Pascal и т. Д., Где есть ключевые слова, имена, литералы и другие словоподобные строки, разделенные пробелами, с XML у меня есть проблема, потому что нет ' т любые слова! Это только обычный текст, чередующийся с разметкой (тегами).
Я подумал, что эти теги и фрагменты простого текста могут быть токенами, что-то вроде этого: [TXT][TAG][TAG][TXT][TAG][TXT][TAG][TAG][TXT]...
, Это было бы вполне разумно, так как SGML не волнует, что находится внутри разделителей разметки. <
а также >
(ну, он распознает специальные инструкции обработки и определения, когда он найдет ?
или же !
как следующий персонаж; комментарии также относятся к этой группе), и токенайзер SGML может стать основой для синтаксического анализатора XML/HTML/XHTML.
Но потом я понял, что может быть <
символы, вставленные в разметку как часть другого синтаксиса: значения атрибутов:-/ Даже если не очень хорошая идея поместить <
символы внутри значений атрибутов (лучше использовать <
для этого), многие браузеры и редакторы имеют дело с этим и относятся к этим <
как часть значения атрибута, а не разделителя тегов.
Это немного усложняет ситуацию, потому что я не вижу способа распознать такую разметку простым детерминированным конечным автоматом (DFA) в лексере. Похоже, он требует отдельного контекста для автомата, когда он находится внутри тега, и другого контекста, когда он встречает значение атрибута. Я думаю, что для этого потребуется стек состояний / контекстов, поэтому DFA может с этим не справиться. Я прав?
Что ты думаешь? Хорошо ли делать токены из тегов (разметки) и простого текста?
Здесь: http://www.antlr.org/wiki/display/ANTLR3/Parsing+XML
используется какая-то другая техника: они относятся <
а также >
(а также </
а также />
) как отдельные токены, так и внутри тегов, которые они используют GENERIC_ID
как символ и т. д. Они обычно переносят большую часть работы на анализатор. Но они также должны изменить контексты для токенизатора: они используют различный контекст в простом тексте и различаются в разметке (но я думаю, что они забыли о контексте значений атрибутов, потому что первое появление >
закончу тег в своем лексере).
Итак, каков наилучший подход для разбора SGML-подобных языков? Лексер действительно используется там? Если да, какие строки составляют токены?
1 ответ
Создав парсеры XML и HTML, у меня есть мнения.
Лексемы вообще должны быть узнаваемыми элементами языка.
Для XML и HTML они в основном соответствуют
- ТАГБЕГИН, вещи в форме <ИМЯ
- TAGEND, в форме >
- TAGCLOSE, в форме NAME>
- TAGENDAND ЗАКРЫТЬ формы /> (только XML)
- ATTRIBUTENAME, в форме NAME
- EQUALSIGN, будучи точно =
- ATTRIBUTEVALUE, являющийся значением точной символьной строки, представленной атрибутом, независимо от кавычек (или даже отсутствия кавычек, для устаревшего HTML). Если в атрибуте есть экранированные коды символов, этот код следует преобразовать в их действительный код символа.
- СОДЕРЖАНИЕ, которое является текстом между TAGEND и TAGBEGIN. Как и ATTRIBUTEVALUES, любые экранированные символы должны быть преобразованы, поэтому CONTENT между foo & lt; bar B> преобразуется в текст foo
Если вы хотите сохранить вызовы сущностей в качестве отдельных токенов, вы можете сделать это, выполнив потоки токенов CONTENT и ENTITYINVOCATION между TAGEND и TAGSTART; зависит от того, какова ваша цель.
Мы можем спорить о том, хотите ли вы создать токен для комментариев HTML/XML или нет. Если вы делаете, вы делаете.
Если мы игнорируем сложности DTD и схем для XML, это все, что вам действительно нужно.
Как это делает лексер, сложнее; с XML и HTML, есть много беспорядка, касающегося выходов во входном потоке, <[CDATA...]> (если я имею это право), который является просто забавной цитатой и исчезает, когда лексема CONTENT производится. Чтобы справиться со всем этим, вам нужен довольно сложный лексерский движок. И да, на практике вам нужны разные лексические состояния ("режимы") для обработки разных частей текста. У меня в основном есть один основной режим для обработки вещей внутри <... > и один основной режим для обработки CONTENT.