この記事は何?

ほとんどタイトル通りです。
順番に読み進めていけば簡単なWebページが表示できるレベルのWebブラウザを作ることができるように執筆していく予定です。
またアルゴリズムだけをなるべくわかり易く解説していきたいので、記事内で紹介するコードは誰でも読める程度の擬似コードです。
自分で実装したい方は、面倒かもしれませんがそれぞれの言語に翻訳してください。

必要な知識としては:

  • HTML/CSSが困らない程度に読める
  • やる気

これだけです。

いろいろとパースする

Webページは基本的にHTMLで書かれていますね。あとCSSも。
HTMLもCSSもそのままではただの文字列であって扱いづらいので、パーサを通してDOMノードを作りましょう。

まずはHTMLパーサのクラスを作ります。HTMLの内容と、パーサが今何文字目を読んでいるのかを保持するための変数を確保します。初期状態でpos0に、bodyはすでにHTMLのコードが入っているとします。

struct Parser {
   string body
   int pos
}

コンパイラなどを作ったことがある方なら ただの字句解析器みたいなものか と思われるかもしれませんが、ここでは知らない人のためにちゃんと説明しようと思います。

たとえば以下のようなHTMLがあるとします。

<html><body>hello</body></html>

とりあえず一文字目から読み進めてみましょうか。現在^の位置にある<を読んでいます。

<html><body>hello</body></html>
^

HTMLで<が見えたら、それはタグであるとすぐにわかりますね。
パーサもそのとおりに実装していきましょう。body内を読んでいて(pos < body.len())、今読んでいる文字が<ならparse_tag()にタグの処理を渡します。
またparse_tag()は処理した結果を返してくるでしょうから、それをnodesに追加していきます。

parse_nodes() {
    nodes = []
    while pos < body.len() {
        if body[pos] == '<' {
            nodes += parse_tag()
        }
    }
    return nodes
}

parse_tag() {
    // 今は省略
}

parse_tag()の中ではタグの名前やアトリビュートを解析していきますが、この記事では簡単にするためにタグの名前だけを処理することにします。したがって、<div>は扱えますが<div style=''>はダメだということです。

さて、<の次には何が来るのかというと、タグの名前ですね。
まずposを一文字分進めて<を飛ばします。(ここからのコードはすべてparse_tag()の中身です)

pos++ 

以下のように、^hを指すようになりました。

<html><body>hello</body></html>
 ^

するとbody[pos]がタグの名前の一文字目となります。タグは英文字が連続したものなので、英文字が続く限り読み進めていきます。

tag_name = "" 
while body[pos].is_alphabet() {
    tag_name += body[pos]
    pos++
}

タグの名前が終われば>が来ます。飛ばしましょう。

pos++

<html><body>hello</body></html>
      ^

ここからは要素

... sorry, coming soon.