WebKit中的html詞法解析

WebKit中的html詞法解析

[email protected]

摘要:webkit源代碼分析,webcore,html解析,htmlparse,htmltoken,htmltokenizer,dlmu2001,瀏覽器,chrome

語言的解析一般分爲詞法分析(lexical analysis)和語法分析(Syntax analysis)兩個階段,WebKit中的html解析也不例外,本文主要討論詞法分析。

詞法分析的任務是對輸入字節流進行逐字掃描,根據構詞規則識別單詞和符號,分詞。

在WebKit中,有兩個類,同詞法分析密切相關,它是HTMLToken和HTMLTokenizer類,可以簡單將HTMLToken類理解爲標記,HTMLTokenizer類理解爲詞法解析器。HTML詞法解析的任務,就是將輸入的字節流解析成一個個的標記(HTMLToken),然後由語法解析器進行下一步的分析。

在XML/HTML的文檔解析中,token這個詞經常用到,我將其理解爲一個有完整語義的單元(也就是分出來的“詞”),一個元素通常對應於3個token,一個是元素的起始標籤,一個是元素的結束標籤,一個是元素的內容,這點同DOM樹是不一樣的,在DOM樹上,起始標籤和結束標籤對應於一個元素節點,而元素內容對應另一個節點。

除了起始標籤(StartTag)、結束標籤(EndTag)和元素內容(Character),HTML標籤還有DOCTYPE(文檔類型),Comment(註釋),Uninitialized(默認類型)和EndOfFile(文檔結束)等類型,參見HTMLToken.h中的Type枚舉。

htmltoken

上圖是HTMLToken類的成員變量,從中我們可以看到一個標記的組成:類型,在字節流中的偏移,數據(m_data,不同的類型具有不同的意義),文檔類型,是否自封閉(對於開始和結束標籤),屬性列表,當前屬性。

HTMLTokenizer就是要從字節流解析出一個個這樣的結構體來,他的實現是基於狀態機來做的,狀態機模型在http://www.w3.org/TR/html5/tokenization.html#tokenization 中已經明確定義,nextToken方法實現了該狀態機。

對有限狀態機不熟悉的童子建議先學習下absurd大大的文章系統程序員成長計劃 - 文本處理 ( ) 狀態機( http://blog.csdn.net/absurd/archive/2009/06/07/4249569.aspx )。

下面以一個簡單的html文檔來複盤狀態機的幾條路線。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN
">

<!--comment -->

<html>

<body>

<a href=”w3c.org”>w3c</a>

</body>

</html>

不考慮類似<html>和<body>之間的回車換行(webkit裏面有做特殊處理,也就是所謂的“authoring convenience”,m_skipLeadingNewLineForListing),從前面的描述中,我們可以確認,該文檔有9個HTMLToken,分別是文檔類型聲明,註釋,html的起始標籤,body的起始標籤,a的起始標籤,a的元素內容,a的介紹標籤,body的結束標籤,html的結束標籤。

起始狀態爲DataState。

1)DOCTYPE

DataState< !DOCTYPE,碰到’<’,進入TagOpenState

TagOpenState<! DOCTYPE, 碰到’!’,進入MarkupDeclarationOpenState狀態

MarkupDeclarationOpenState<!D OCTYPE,碰到’D’,匹配DOCTYPE和--字數都不夠,保持現狀

MarkupDeclarationOpenState<!DOCTYPE ,匹配doctype,進入DOCTYPEState狀態(HTMLToken的type爲DOCTYPE)

DOCTYPEState :  <!DOCTYPE   html PUBL,碰到空格,進入BeforeDOCTYPENameState狀態

BeforeDOCTYPENameState:   <!DOCTYPE h tml PUBL,碰到’h’,進入DOCTYPENameState

DOCTYPENameState :  <!DOCTYPE ht ml PUBL,碰到’t’,保持原狀態,提取html作爲文檔類型

DOCTYPENameState :  <!DOCTYPE html   PUBL,碰到空格,進入AfterDOCTYPENameState狀態。(HTMLToken的m_data爲

                                  html)

AfterDOCTYPENameState :<!DOCTYPE html P UBLIC,碰到’P’,還未能匹配Public或者system,保持狀態

AfterDOCTYPENameState :<!DOCTYPE html PUBLIC ,匹配public,進入AfterDOCTYPEPublicKeywordState

AfterDOCTYPEPublicKeywordState :<!DOCTYPE html PUBLIC  "-/,碰到空格,進入BeforeDOCTYPEPublicIdentifierState

BeforeDOCTYPEPublicIdentifierState :<!DOCTYPE html PUBLIC " -/,碰到’”’,進入

                                                                 DOCTYPEPublicIdentifierDoubleQuotedState

DOCTYPEPublicIdentifierDoubleQuotedState :<!DOCTYPE html PUBLIC "- /,碰到’-‘,保持狀態,提取m_publicIdentifier

DOCTYPEPublicIdentifierDoubleQuotedState :<!DOCTYPE html PUBLIC "-/…nal//EN" >,碰到’”’,進入

                                                             AfterDOCTYPEPublicIdentifierState狀態。(HTMLToken的m_publicIdentifier確定)

AfterDOCTYPEPublicIdentifierState :<!DOCTYPE html PUBLIC "-/…nal//EN">  碰到’>’,進入DataState狀態,完成文檔類型

                                                           的解析

2)COMMENT

DataState< !--comment -->,碰到’<’,進入TagOpenState

TagOpenState<! --comment -->, 碰到’!’,進入MarkupDeclarationOpenState狀態

MarkupDeclarationOpenState<!- -comment -->,碰到’-’,匹配DOCTYPE和--字數都不夠,保持現狀

MarkupDeclarationOpenState<!-- comment -->,匹配--,進入CommentStartState狀態(HTMLToken的type爲COMMENT)

CommentStartState :  <!--c omment -->,碰到’c’,進入CommentState

CommentState :<!--comment - ->,碰到’-‘,進入CommentEndDashState狀態(HTMLToken的m_data爲comment)

CommentEndDashState :  <!--comment -- >,碰到’-‘,進入CommentEndState狀態

CommentEndState :<!--comment --> ,碰到’>‘,進入DataState狀態,完成解析。

3)起始標籤a

DataState< a href=”w3c.org ”>,碰到’<’,進入TagOpenState狀態

TagOpenState<a   href=”w3c.org ”>,碰到’a’,進入TagNameState狀態(HTMLToken的type爲StartTag)

TagNameState<a  href=”w3c.org ”>,碰到空格,進入BeforeAttributeNameState狀態(HTMLToken的m_data爲a)

BeforeAttributeNameState<a h ref=”w3c.org ”>,碰到‘h’,進入AttributeNameState狀態

AttributeNameState<a href= ”w3c.org ”>,碰到‘=’,進入BeforeAttributeValueState狀態(HTMLToken

                                                      屬性列表中加入一個屬性,屬性名爲href)

BeforeAttributeValueState :  <a href= w3c.org ”>,碰到‘“’,進入AttributeValueDoubleQuotedState狀態

AttributeValueDoubleQuotedState<a href= ”w 3c.org ”>,碰到‘w’,保持狀態,提取屬性值

AttributeValueDoubleQuotedState<a href= ”w3c.org >,碰到‘“’,進入AfterAttributeValueQuotedState

                                                              (HTMLToken當前屬性的值爲w3c.org).

AfterAttributeValueQuotedState :  <a href= ”w3c.org ”> ,碰到‘>’,進入DataState,完成解析。

在完成startTag的解析的時候,會在解析器中存儲與之匹配的end標籤(m_appropriateEndTagName),等到解析end標籤的時候,會同它進行匹配(語法解析的時候)。

html,body起始標籤類似a起始標籤,但沒有屬性解析

4)a元素

DataStatew 3c</a>,碰到’w’,維持原狀態,提取元素內容(HTMLToken的type爲character)。

DataStatew3c< /a>,碰到’<’,完成解析,不consume ’<’。(HTMLToken的m_data爲w3c)。

5)a結束標籤

DataStatew3c< /a>,碰到’<’,進入TagOpenState。

TagOpenStatew3c</ a>,碰到’/’,進入到EndTagOpenState。(HTMLToken的type爲endTag)。

EndTagOpenStatew3c</a >,碰到’a’,進入到TagNameState。

TagNameStatew3c</a> ,碰到’>’,進入到DataState,完成解析。

通過以上的覆盤,一個標記的token過程清晰呈現在眼前,基本上就是實現http://www.w3.org/TR/html5/tokenization.html 這一章的一個過程,html的規範是相當寬鬆的,所以詞法解析要考慮到的問題很多,html5 specfication在這方面爲實現者做了絕大部分工作。

另外,html的語法解析會影響詞法解析,比如語法解析在解析到head裏面title的起始標籤後,會將htmltokenizer解析器的狀態設置爲RCDATAState。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章