这是一个从未编写过解析器/词法分析器的人的noob问题.
我正在用PHP编写CSS的标记器/解析器(请不要重复’OMG,为什么用PHP?’).语法由W3C整齐地记录下来here (CSS2.1)和here (CSS3, draft).
它是21个可能令牌的列表,所有(但是两个)都不能表示为静态字符串.
我当前的方法是一遍又一遍地循环包含21个模式的数组,执行if(preg_match())并通过匹配减少源字符串匹配.原则上这非常好.但是,对于1000行的CSS字符串,这需要2到8秒的时间,这对我的项目来说太多了.
现在我正在敲打我的脑袋,其他解析器如何标记化并在几秒钟内解析CSS.好吧,C总是比PHP快,但是,有没有明显的D’哦!我陷入了什么?
我做了一些优化,比如检查’@’,’#’或’“’作为剩余字符串的第一个字符,然后仅应用相关的正则表达式,但这并未带来任何出色的性能提升.
到目前为止我的代码(片段):
$TOKENS = array(
'IDENT' => '...regexp...',
'ATKEYWORD' => '@...regexp...',
'String' => '"...regexp..."|\'...regexp...\'',
//...
);
$string = '...CSS source string...';
$stream = array();
// we reduce $string token by token
while ($string != '') {
$string = ltrim($string, " \t\r\n\f"); // unconsumed whitespace at the
// start is insignificant but doing a trim reduces exec time by 25%
$matches = array();
// loop through all possible tokens
foreach ($TOKENS as $t => $p) {
// The '&' is used as delimiter, because it isn't used anywhere in
// the token regexps
if (preg_match('&^'.$p.'&Su', $string, $matches)) {
$stream[] = array($t, $matches[0]);
$string = substr($string, strlen($matches[0]));
// Yay! We found one that matches!
continue 2;
}
}
// if we come here, we have a syntax error and handle it somehow
}
// result: an array $stream consisting of arrays with
// 0 => type of token
// 1 => token content
解决方法: