使用ANTLR解析CSS - 边缘情况

9

我正在尝试使用ANTLR解析CSS,或者至少是基础内容。但是我的词法分析规则存在一些问题。问题在于ID选择器和十六进制颜色值之间的歧义性。为了清晰起见,使用简化的语法,考虑以下输入:

#bbb {
  color: #fff;
}

和以下解析器规则:

ruleset : selector '{' property* '}';
selector: '#' ALPHANUM;
property: ALPHANUM ':' value ';' ;
value: COLOR;

还有这些词法分析器标记:

ALPHANUM : ('a'..'z' | '0'..'9')+;
COLOR : '#' ('0'..'9' | 'a'..'f')+;

这是行不通的,因为#bbb被标记为颜色标记,即使它应该是一个选择器。如果我更改选择器,使其不以十六进制字符开头,则可以正常工作。我不确定如何解决这个问题。是否有一种方法告诉ANTLR仅在特定位置将特定标记视为颜色标记?比如说,在属性规则中,我可以安全地假设它是颜色标记。如果不是,请将其视为选择器。
非常感谢您的帮助!
解决方案:事实证明,我在语法上试图做太多的事情,我应该在代码中使用AST处理。CSS有太多不明确的标记无法可靠地分成不同的标记,因此我现在使用的方法基本上是对特殊字符(如“#”、“。”、“:”和大括号)进行标记化,并在消费者代码中进行后处理。效果要好得多,而且容易处理边缘情况。
4个回答

8

尝试将词法分析器文件中的#从COLOR移动到它自己的位置,如下所示:

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

然后,在您的解析器规则中,您可以这样做:
color: HASH (LLETTERS | ALPHANUM)+;
selector: HASH (ULETTERS | LLETTERS) (ULETTERS | LLETTERS | NUMBERS)*;

这使您能够在语法上指定差异,大致可以描述为上下文,而不是词汇,可以粗略地描述为外观。如果某些东西的含义取决于它所在的位置,则应在语法中指定该差异,而不是在词法分析器中。

请注意,颜色和选择器具有相同的定义。词法分析器通常是从将输入字符串转换为语法的模块中分离出来的一个单独阶段,因此具有歧义的词汇表是无效的(正如指出的那样,bbb可以是十六进制或小写字母字符串)。因此,数据有效性检查需要在其他地方进行。


这仍然不起作用。问题在于 bbb(或任何以 0..9 | a..f 开头的内容)将被标记为 HEXSTRING。这将防止 #bbb 被匹配为选择器。 - Erik van Brakel
实际上,我弄反了。我相信由于bbb既是有效的字符串又是有效的十六进制字符串,你需要进行软件端数据有效性检查。 - Walt W
这就是我担心的。希望在StackOverflow上有一个antlr大师能够证明你是错的 :/ - Erik van Brakel
是的,可能有更好的方法。但那应该可以工作。抱歉,我好像有一段时间没有写解析器了 :-[ - Walt W
看起来你的示例不完整。 - CSchulz

2
为了重申Walt所说的,CSS 2.1附录G:CSS语法中说要对HASH进行词法分析,然后(取决于它相对于其他标记的位置)将HASH解析为simple_selectorhexcolor之一。
词法分析器定义了以下标记...
"#"{name}       {return HASH;}

"...语法包括以下规则..."
hexcolor
  : HASH S*
  ;

simple_selector
  : element_name [ HASH | class | attrib | pseudo ]*
  | [ HASH | class | attrib | pseudo ]+
  ;

这意味着基于语法的解析器将允许非十六进制十六进制颜色。我会在分析/解释词法分析和语法树的代码中稍后检测到非十六进制十六进制颜色。

是的,我熟悉那个附录。这是我构建语法时使用的来源之一。但对我来说并没有解决问题 :( - Erik van Brakel
@Erik:你看过 http://www.antlr.org/grammar/list 上提供的 CSS 语法了吗? - Vineet Reynolds
是的,我已经查看了CSS 3语法,它显示相同的错误。 - Erik van Brakel
“不过这并没有解决我的问题” -- 什么问题?如果你按照规范实现语法,它是有效的。也许你的问题是你试图重写规定语法使其比规范更严格,或者(我不知道为什么)将错误检查移到解析器中。 - ChrisW
也许我对它的理解有误,或者在使用ANTLR时出了些问题。我会再次仔细研究一下,并在那时回答这个问题。可能是明天或后天。 - Erik van Brakel
与ANTLR(我没有尝试过)不同,我使用了GOLD解析器使指定的语法可机读,但无论如何都起作用了。 - ChrisW

0

通过谷歌搜索来到这里,发现一个好的资源,一个真正的实现。对于那些寻找完整的CSS Antlr语法的人,可以查看this 语法文件。这可以给你一个想法,或者你可以直接使用它。


0

为了从多种选择中做出决策,ANTLR有两个选项:

  • 语法谓词
  • 语义谓词

这是来自antlr语法库(css2.1 g)的:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接