Dev Study
← Rust で小さなブラウザを作る コース

17. CSS のトークン — 先頭の数文字で種類が決まる

CSS のは HTML と違ってではなく、「先頭の 1〜3 文字を見て種類を決め、その種類に必要なだけ読む」形です(CSS Syntax Level 3 §4 の consume a )。空白が続けば 1 つの <whitespace-token>、" か ' なら <string-token>、数字(または +/-/. に続く数字)なら数値、英字や _ や非 なら、# に名前が続けば <hash-token>、@ に名前が続けば <at-keyword-token>、どれでもない 1 文字は <delim-token>。

仕様のトークンは 24 種類あります。参照実装はそのうち使うものだけを CssToken に持ちます。Ident / Function(識別子の直後が "(")/ AtKeyword / Hash / Str / Number / Percentage / Dimension(数と単位: 16px → (16.0, ""))/ Delim / Whitespace / Colon / Semicolon / Comma / 括弧 6 種。<url-token> や <bad-string-token>、CDO / CDC(<!-- と -->)は省きました。

読みどころが 2 つあります。1 つは #main と #ff0000 がどちらも Hash になること。の ID なのか色なのかは、字句解析では決めません。でどこに出てきたかで決めます。もう 1 つは .note が Delim('.') と Ident("note") の 2 トークンになること。クラスセレクタという単位は字句解析には無く、構文解析で組みます。コメント /* */ はトークンにならず、読み捨てます。

下のコードを実行すると、5 つの入力のトークン列が出ます。数値の読み方(-2、.5、1.5em、50%)と、rgb( が Function になるところを見てください。

本物のブラウザでは: の CSS 字句解析は css_tokenizer.h の CSSTokenizer で、TokenizeSingle() が CSSParserToken を 1 つ返す形です。この回の next_token() と同じ『1 つずつ返す』設計です。Firefox は Firefox 57 から Servo 由来の Rust のスタイルシステム(、servo/components/style)を使い、その README に「 で解析する」とあります。つまり Firefox の CSS 字句解析は Rust で書かれていて、この回で書いた Rust のコードに最も近い本物です。

開発のどこに活かすか: 「字句解析は文脈を見ない。文脈は構文解析が見る」という分担は、どの言語処理でも同じです。自前の設定記法や検索言語を作るとき、字句解析に文脈判断を持ち込むと(# を見て ID か色かを決めようとすると)すぐに破綻します。トークンを薄く保ち、意味づけは次の段に任せる、が定石です。

点線の付いた語はタップすると説明が出ます。用語集を開く →

▶ サンプルコードを実行してみよう(自由に書き換えてOK)

Rust

手元で動かす(配布物)

図やコードに出てくる用語(タップで説明)

サンプルコードで身につける(3本) →

学んだ概念を、素朴な例から実務寄りの例まで3つの具体例で確認します。

公式ドキュメントで詳しく ↗