Разбор CSS с помощью ANTLR - крайние случаи - PullRequest
8 голосов
/ 25 августа 2009

Я пытаюсь проанализировать 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 ]

8 голосов
/ 25 августа 2009

Попробуйте переместить # в вашем файле лексера из COLOR в его собственную вещь, например:

LLETTERS: ( 'a'..'z' )
ULETTERS: ( 'A'..'Z' )
NUMBERS: ( '0'..'9' )
HASH : '#';

Затем в правилах вашего парсера вы можете сделать это так:

color: HASH (LLETTERS | ALPHANUM)+;
selector: HASH (ULETTERS | LLETTERS) (ULETTERS | LLETTERS | NUMBERS)*;

и т.д.

Это позволяет вам указать разницу грамматически, что можно приблизительно описать как контекстуально, а не как лексически, что можно приблизительно описать как внешний вид. Если значение чего-либо меняется в зависимости от того, где оно находится, это различие должно быть указано в грамматике, а не в лексере.

Обратите внимание, что цвет и селектор - это одно и то же определение. Лексеры обычно являются отдельным этапом от модуля, который переводит входную строку в грамматику, поэтому недопустимо иметь неоднозначный лексикон (как было отмечено, bbb может быть шестнадцатеричным или строчной буквой). Таким образом, проверка достоверности данных должна быть сделана в другом месте.

2 голосов
/ 25 августа 2009

В дополнение к тому, что сказал Уолт, Приложение 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 ]+
  ;

Это означает, что синтаксический анализатор, основанный на грамматике, допускает не-шестнадцатеричный шестнадцатеричный цвет.

Позже я обнаружил бы не-шестнадцатеричный цвет в коде, который анализирует / интерпретирует синтаксическое дерево синтаксиса с синтаксическим анализом и синтаксическим анализом.

0 голосов
/ 10 июля 2013

Просто пришел сюда, погуглив, и нашел хороший ресурс, реальный смысл. Для тех, кто приходит и ищет полную грамматику CSS Antlr, взгляните на этот файл грамматики. Это может дать вам идею или вы можете использовать ее напрямую.

0 голосов
/ 10 июля 2012

Чтобы принять решение из нескольких альтернатив, ANTLR имеет два варианта,

  • синтаксические предикаты
  • семантические предикаты

Это из библиотеки грамматики antlr (css2.1 г):

simpleSelector
    : elementName 
        ((esPred)=>elementSubsequent)*

    | ((esPred)=>elementSubsequent)+
    ;

esPred
    : HASH | DOT | LBRACKET | COLON
    ;

elementSubsequent
    : HASH
    | cssClass
    | attrib
    | pseudo
    ;

cssClass
    : DOT IDENT
    ;

elementName
    : IDENT
    | STAR
    ;

Используется для синтаксических предикатов.

Ссылка на грамматику: http://www.antlr.org/grammar/1240941192304/css21.g

...