演習として、PHP で基本的なレクサーを作成しています。現在、私はPHPソースをレックス化し、HTMLタグを介して強調表示されたソースを出力していますが、いくつかの広範な正規表現一致だけでなく、実際のトークン名などを使用しています。
私が設定している方法は、PHP ソースを 1 文字ずつ読み込むことです。現在の文字をチェックして、現在のトークンが何であるかを判断し、適切なパターンに一致する次のx文字を読み取ります。
たとえば、現在の文字が " の場合、エスケープ \ が先行していない別の " に遭遇するまで、すべての文字を読み込みます。これは悪い方法ですか?私が見て理解した他の唯一の方法は、大規模な正規表現をコンパイルし、すべてのトークンを一度に照合するクラスを作成することでしたが、それは私には柔軟ではないようです。
考え?
$str = '';
$php = str_replace( "\r\n", "\n", $php );
$php = str_split( $php );
$len = count( $php );
$keyword = '';
for ( $i = 0; $i < $len; $i++ ) {
$char = $php[$i];
// Detect PHP strings and backtick execution operators
if ( strpos( self::STRING_CHARACTERS, $char ) !== FALSE ) {
$string = $char;
$opening_quote = $char;
$escaped = FALSE;
while ( isset( $php[++$i] ) && ( $escaped || $php[$i] != $opening_quote ) ) {
$string .= $php[$i];
if ( $php[$i] == '\\' ) {
$escaped = !$escaped;
}
}
$string .= $php[$i];
if ( $opening_quote == "'" ) {
$str .= '<span class="php-string php-single-quoted-string">' . htmlspecialchars( $string ) . '</span>';
} else if ( $opening_quote == '"' ) {
$str .= '<span class="php-string php-double-quoted-string">' . htmlspecialchars( $string ) . '</span>';
} else if ( $opening_quote == '`' ) {
$str .= '<span class="php-execution-operator php-backtick">' . htmlspecialchars( $string ) . '</span>';
}
continue;
}
$str .= $char;
}