Разбор 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, взгляните на этот файл грамматики. Это может дать вам идею или вы можете использовать ее напрямую.

Другие вопросы по тегам