Неоднозначная грамматика с генератором синтаксического анализа Lemon

#css #parsing #lemon

#css #синтаксический анализ #lemon

Вопрос:

Итак, в основном я хочу проанализировать структуру CSS-кода на PHP, используя лексер / анализатор, сгенерированный пакетами PEAR PHP_LexerGenerator и PHP_ParserGenerator. Моя цель — анализировать файлы, подобные этому:

 selector, selector2 {
    prop: value;
    prop2 /*comment */ :
       value;

    subselector {
        prop: value;
        subsub { prop: value; }
    }
}
  

Все это прекрасно, пока у меня нет псевдоклассов. Псевдоклассы позволяют добавлять : и имя CSS ( [a-z][a-z0-9]* ) к элементу, как в a.menu:visited . Будучи несколько ленивым, анализатор не имеет списка допустимых псевдоклассов и принимает все для имени класса.

Моя грамматика (игнорирующая все особые случаи и пробелы) выглядит следующим образом:

 document   ::= (<rule>)*

rule       ::= <selector> '{' (<content>)* '}'

content    ::= <rule>
content    ::= <definition>

definition ::= <name> ':' <name> ';'

//             h1     .class.class2#id    :visited
<selector> ::= <name> (('.'|'#') <name>)* (':' <name>)?
  

Теперь, когда я пытаюсь проанализировать следующее

 h1 {
    test:visited {
        simple: case;
    }
}
  

Анализатор жалуется, что ожидал, что за двойным двоеточием будет следовать <name> . Таким образом, он пытается прочитать simple: как <selector> (просто посмотрите на подсветку синтаксиса SO).

Является ли моей ошибкой то, что анализатор не может выполнить достаточно обратное отслеживание, чтобы попробовать <definition> правило? Или Lemon просто недостаточно мощный, чтобы выразить это? Если да, то что я могу сделать, чтобы заставить анализатор работать с этой грамматикой?

Комментарии:

1. Ваша грамматика не будет обрабатывать select1, select2 { ... } обозначения. Нет правила, которое обрабатывает «список селекторов, разделенных запятыми».

2. В вашем вопросе упоминается «двойное двоеточие», но во входных данных примера нет ‘::’ и нет ничего, что обрабатывает двойное двоеточие в грамматике.

Ответ №1:

Ваш вопрос касается PHP_ParserGenerator и PHP_LexerGenerator. Код генератора синтаксического анализа помечен как «не поддерживается», что не предвещает ничего хорошего.

Синтаксис, который вы используете для грамматики, неприемлем для Lemon, поэтому вам нужно уточнить, почему, по вашему мнению, генератор синтаксического анализа должен его принимать. Вы упоминаете проблему с ‘ожидаемым a <name> после двойного двоеточия, но ни в вашей грамматике, ни в вашем примере ввода нет двойного двоеточия, что затрудняет помощь вам.

Я думаю, что эта грамматика Lemon эквивалентна той, которую вы показали:

 document        ::= rule_list.
rule_list       ::= .
rule_list       ::= rule_list rule.
rule            ::= selector LBRACE content_list RBRACE.
content_list    ::= .
content_list    ::= content_list content.
content         ::= rule.
content         ::= definition.
definition      ::= NAME COLON NAME SEMICOLON.
selector        ::= NAME opt_dothashlist opt_colonname.
opt_dothashlist ::= .
opt_dothashlist ::= dot_or_hash NAME.
dot_or_hash     ::= DOT.
dot_or_hash     ::= HASH.
opt_colonname   ::= COLON NAME.
  

Однако, когда он компилируется, Lemon жалуется 1 parsing conflicts , и выходной файл показывает:

 State 2:
          definition ::= NAME * COLON NAME SEMICOLON
          selector ::= NAME * opt_dothashlist opt_colonname
     (10) opt_dothashlist ::= *
          opt_dothashlist ::= * dot_or_hash NAME
          dot_or_hash ::= * DOT
          dot_or_hash ::= * HASH

                         COLON shift  10
                         COLON reduce 10  ** Parsing conflict **
                           DOT shift  13
                          HASH shift  12
               opt_dothashlist shift  5
                   dot_or_hash shift  7
  

Это означает, что он не уверен, что делать с двоеточием; это может быть ‘opt_colonname’ частью ‘селектора’ или это может быть частью ‘definition’:

 name1:name4 : name2:name3 ;
  

Вы имели в виду разрешить такой синтаксис? Номинально, согласно грамматике, это должно быть допустимо, но

 name1:name4;
  

также должно быть допустимым. Я думаю, что для устранения этих неоднозначностей требуется 2 или 3 токена lookahead (так что ваша грамматика не LALR(1), а LALR (3)).

В частности, пересмотрите свое определение «селектора».