解析HTML文档
为了让引擎能够理解HTML文档,需要将文档中的每个单词划分成可被程序理解的标记,因此,需要词法分析器是必须的,也就是tokenizer模块。在仔细分析了HTML的结构之后,发现这个tokenizer的设计与其他编程语言的词法分析器可以有一些不同,只需要设计6个token,并非像其他编程语言那样需要为每个关键字,数字,字符串以及操作符定义token。但是要做到这一点,就需要让这个tokenizer具有一点文法分析的能力。6个标记的定义如下:
namespace token
{
enum t
{
tag_terminator,
element, attr, value, content,
eof
};
}
这6个token基本上可以描述一个HTML文档。例如一个简单的HTML
<BODY text="blue">This isLitecore</BODY>
通过tokenizer看到的就是
element attr value content tag_terminator eof
其实tokenizer省略掉两种token,一个是空白符(空格符,换行符和制表符),另一个是注释。这两种token直接在tokenizer内部吃掉,对外部来说就降低了复杂度。另外tokenizer还预留了一组特别的接口,这些接口的目的是保证在HTML文档的下载的过程中,tokenizer就可以开始工作,如果网速很慢并不影响对HTML的解析,当成功处理一个完整的元素,并被判断可以显示的时候,引擎就可以将分析得到的元素树发送到page_typesetter模块进行排版并渲染。
tokenizer还需要特别处理一种情况。例如:
<TEXTAREA><P>Hello,Litecore</P><TEXTAREA>
被TEXTAREA包围着的文本被解析成它的内容,其中的<P>不再解析为P元素。tokenizer把类似于TEXTAREA元素行为的元素归类为scope,这是tokenizer定义的一种行为类型。
标准冲突
在某些情况下,标准定义的行为并不被当前主流浏览器支持。因此,在这种个别的情况下Litecore也必须抛弃对标准的支持,这样可以保证Litecore的渲染效果与其它浏览器保持一致。例如在HTML4.01规范的B3.1中描述 紧跟开始标签的换行符必须被忽略掉,后面紧接着是结束标签的换行符也同样地被忽略掉。也就是说下面两种情况的渲染效果应该保持一致:
<A>Hello</A>
和
<A>
Hello
</A>
这个例子可以在浏览器中保持一致,但是原因并非是浏览器遵守了规范。再看一个例子
<A>Hello</A><A>Litecore</A>
和
<A>Hello</A><A>
Litecore</A>
很明显,在其他主流的浏览器中,后一条Hello与Litecore被空格分开,与上一条并非一致。
Litecore将这些问题都置于tokenizer中解决,其原因也很简单,仅仅是为了降低后面模块的复杂度。