This is a noob question from someone who hasn't written a parser/lexer ever before.
Ben ('OMG, neden PHP?' Ile tekrar etmeyiniz) PHP CSS için tokenizer / ayrıştırıcı yazıyorum. Sözdizimi W3C tarafından aşağı yazılır düzgünce here (CSS2.1) ve here (CSS3, draft).
Tüm (ama iki) statik dizeleri olarak temsil edilemez, 21 olası belirteçleri bir listesi.
Benim şu anki yaklaşım if (preg_match())
yapmak ve maçın tarafından kaynak dize maçı azaltmak, tekrar ve tekrar 21 desenleri içeren bir dizi döngü olduğunu. Prensip olarak bu gerçekten iyi çalışıyor. Ancak, 1000 satır CSS dize için bu benim proje için çok fazla 2 ve 8 saniye arasında bir şey alır.
Şimdi diğer ayrıştırıcılarda and saniye kesirleri CSS ayrıştırmak tokenize nasıl başımı beceriyor ediyorum. Tamam, C is her zaman PHP daha hızlı, ama yine de, herhangi bir bariz D'Oh! s ben içine düştüğü vardır?
Ben ilk kalan dize karakter ve sonra sadece ilgili regexpi uygulamak olarak '@' için kontrol gibi bazı optimizasyonlar, '#' veya '"' yaptı, ancak bu herhangi bir büyük performans artışları getirdi yoktu.
Benim kodu (pasajı) şimdiye kadar:
$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