Неоднозначная грамматика с Lemon Parser Generator - PullRequest
2 голосов
/ 10 октября 2011

Таким образом, я хочу проанализировать структуру 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>?Или Лимон просто недостаточно силен, чтобы выразить это?Если да, что я могу сделать, чтобы парсер работал с этой грамматикой?

1 Ответ

3 голосов
/ 10 октября 2011

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

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

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

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.

Однако, когда он скомпилирован, Лимон жалуется 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 селектора или часть определения:

name1:name4 : name2:name3 ;

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

name1:name4;

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

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

...