所以基本上我想在PHP中解析结构CSS代码,使用由PEAR包PHP_LexerGenerator和PHP_ParserGenerator生成的词法分析器/解析器。我的目标是解析这样的文件:
selector, selector2 {
prop: value;
prop2 /*comment */ :
value;
subselector {
prop: value;
subsub { prop: value; }
}
}
只要我没有伪类,这一切都很好。 Pseudoclasses允许它向元素添加:
和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>
规则,这是我的错误吗?或者柠檬是不是足够强大来表达这个?如果是这样,我该怎么做才能让解析器使用这个语法?
答案 0 :(得分:3)
您的问题询问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.
然而,在编译时,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
这意味着它不确定如何处理结肠;它可能是'selector'的'opt_colonname'部分,也可能是'定义'的一部分:
name1:name4 : name2:name3 ;
你的意思是允许这样的语法吗?名义上,根据语法,这应该是有效的,但
name1:name4;
也应该有效。我认为它需要2或3个前瞻标记来消除这些歧义(所以你的语法不是LALR(1)而是LALR(3))。
特别要检查你对'选择器'的定义。