Разбор CSS с помощью ANTLR - крайние случаи
Я пытаюсь разобрать CSS, или, по крайней мере, основы, используя ANTLR. Я сталкиваюсь с несколькими проблемами с моими правилами лексера все же. Проблема заключается в неоднозначности между селекторами идентификаторов и шестнадцатеричными значениями цвета. Для упрощения рассмотрим упрощенную грамматику:
#bbb {
color: #fff;
}
и следующие правила парсера:
ruleset : selector '{' property* '}';
selector: '#' ALPHANUM;
property: ALPHANUM ':' value ';' ;
value: COLOR;
и эти лексерные токены:
ALPHANUM : ('a'..'z' | '0'..'9')+;
COLOR : '#' ('0'..'9' | 'a'..'f')+;
Это не будет работать, потому что #bbb маркируется как токен COLOR, даже если он должен быть селектором. Если я изменю селектор, чтобы он не начинался с шестнадцатеричного символа, он работает нормально. Я не уверен, как решить это. Есть ли способ сказать ANTLR, что нужно обрабатывать определенный токен только как токен COLOR, если он находится в определенной позиции? Скажем, если это в правиле свойств, я могу смело предположить, что это цветной маркер. Если это не так, относитесь к нему как к селектору.
Любая помощь будет оценена!
Решение: Оказывается, я пытался сделать слишком много в грамматике, с которой мне, вероятно, следовало бы разобраться в коде, использующем AST. В CSS слишком много неоднозначных токенов, чтобы надежно разделить их на разные токены, поэтому подход, который я сейчас использую, в основном состоит в том, что я в основном использую специальные символы, такие как "#", ".", ":" И фигурные скобки, и выполняю постобработку в потребительский код. Работает намного лучше, и легче справиться с крайними случаями.
4 ответа
Попробуйте переместить # в вашем файле лексера из COLOR в отдельную вещь:
LLETTERS: ( 'a'..'z' )
ULETTERS: ( 'A'..'Z' )
NUMBERS: ( '0'..'9' )
HASH : '#';
Затем в правилах вашего парсера вы можете сделать это так:
color: HASH (LLETTERS | ALPHANUM)+;
selector: HASH (ULETTERS | LLETTERS) (ULETTERS | LLETTERS | NUMBERS)*;
и т.п.
Это позволяет задавать разницу грамматически, что можно приблизительно описать как контекстуально, а не как лексически, что можно приблизительно описать как внешний вид. Если значение чего-либо меняется в зависимости от того, где оно находится, это различие должно быть указано в грамматике, а не в лексере.
Обратите внимание, что цвет и селектор - это одно и то же определение. Лексеры, как правило, являются отдельным этапом от модуля, который переводит входную строку в грамматику, поэтому недопустимо иметь неоднозначный лексикон (как было отмечено, bbb может быть шестнадцатеричным или строчной буквой). Таким образом, проверка достоверности данных должна быть сделана в другом месте.
В дополнение к тому, что сказал Уолт, Приложение G. Грамматика CSS 2.1 говорит lex HASH
и затем (в зависимости от его положения относительно другого токена) проанализировать HASH
либо как simple_selector
или как hexcolor
,
Лексер определяет следующий токен...
"#"{name} {return HASH;}
... и грамматика включает в себя следующие правила...
hexcolor
: HASH S*
;
simple_selector
: element_name [ HASH | class | attrib | pseudo ]*
| [ HASH | class | attrib | pseudo ]+
;
Это означает, что синтаксический анализатор, основанный на грамматике, допускает не-шестнадцатеричный hexcolor.
Позже я бы обнаружил не-шестнадцатеричный цвет в коде, который анализирует / интерпретирует синтаксическое дерево lexed+parsed.
Чтобы принять решение из нескольких альтернатив, ANTLR имеет два варианта:
- синтаксические предикаты
- семантические предикаты
Это из библиотеки грамматики antlr (css2.1 g):
simpleSelector: elementName ((EsPred)=>elementSubsequent)* | ((EsPred)=>elementSubsequent)+; esPred: HASH | ТОЧКА | LBRACKET | ДВОЕТОЧИЕ; elementSubsequent: HASH | CssClass | Attrib | псевдо; CssClass: DOT IDENT; ELEMENTNAME: IDENT | СТАР;
Это используется для синтаксических предикатов.
Ссылка на грамматику: http://www.antlr.org/grammar/1240941192304/css21.g
Просто пришел сюда путем поиска в Google и нашел хороший ресурс, реальный смысл. Для тех, кто приходит и ищет полную грамматику CSS Antlr, взгляните на этот файл грамматики. Это может дать вам идею или вы можете использовать ее напрямую.