内联结构
一旦解析完所有输入,将闭合所有开启的块。
然后我们“遍历树”,访问每个节点,并将段落和标题的原始字符串内容按内联解析。此时我们已经看到了所有链接引用定义,因此我们可以随时解析引用链接。
document
block_quote
paragraph
str "Lorem ipsum dolor"
softbreak
str "sit amet."
list (type=bullet tight=true bullet_char=-)
list_item
paragraph
str "Qui "
emph
str "quodsi iracundia"
list_item
paragraph
str "aliquando id"
注意第一段中的行尾是如何被解析为softbreak
的,并且第一个列表项中的星号已成为emph
。
一个解析嵌套强调和链接的算法。迄今为止,内联解析最棘手的部分是处理强调,加强的强调,链接和图像。 这是使用以下算法完成的。
当我们解析内联碰到以下符号时
- 一系列
*
或者_
字符, - 一个
[
或者![
我们插入一个带有这些符号作为文字内容的文本节点,然后我们将一个指向这个文本节点的指针添加到分隔符栈。
分隔符栈是一个双向链表。每个元素都包含一个指向文本节点的指针,以及以下信息
- 分隔符的类型 (
[
,![
,*
,_
) - 分隔符的数量
- 分隔符是否启用(可以作为开启符号), 并且
- 这些分隔符是否是潜在的开始符号或者关闭符号或者两者都是(取决于何种分隔符在其前或者在其后)。
当我们遇到]
时,调用 查找链接或图片 过程(见下文)。
当输入完成时,我们调用 解析强调 过程,此时 stack_bottom
= NULL.
查找链接或图片在分隔符栈顶部开始,向后查找开启的 [
或![
分隔符。
- 如果找不到,则返回一个字面上的字符
]
- 如果找到,但是其未启用,则从栈中删除未启用的分隔符然后返回一个字面上的字符
]
- 如果找到并且其已启用,则继续解析查看是否有内联链接/图片,引用链接/图片,紧凑的的引用链接/图片,或者快捷的引用链接/图片
- 如果没有,则移除栈中的开始分隔符,并返回一个字面上的字符
]
- 如果有
- 返回一个链接或图像节点,其子节点是开始分隔符指向的文本节点后的内联内容
- 在这些内联内容上运行 解析强调 ,将
[
作为stack_bottom
- 移除开始分隔符
- 如果我们有一个链接(且不是图像),我们还会在开始分隔符之前将所有
[
分隔符设置为未启用。(这将阻止我们在链接中获取链接。)
- 如果没有,则移除栈中的开始分隔符,并返回一个字面上的字符
解析强调的变量stack_bottom
设置了一个在 分隔符栈中下行查找的下限。如果其值为 NULL,我们可以一直查到栈底,否则,我们将在stack_bottom
之前停止。
让current_position
指针指向 分隔符栈上栈底之上的元素(或者是第一个元素,如果stack_bottom
值为 NULL)。
我们跟踪每个分隔符类型为(*
,_
)的openers_bottom
。以及每个结束分隔符路程的长度(3 取模)。将其初始化为stack_bottom
。
然后我们重复以下过程直到我们用完所有的闭合符号:
- 在分隔符堆栈中向前移动
current_position
(如果需要),直到我们找到第一个具有分隔符*
或_
的潜在闭合符号。(这将是距离输入开头最近的位置 – 按解析顺序的第一个。) - 现在,回顾堆栈(保持在
stack_bottom
和此分隔符类型的openers_bottom
之上)匹配第一个潜在的开始符号(“匹配”意味着相同的分隔符)。 - 如果找到一个:
- 探明这是强调还是加强的强调,如果开始符号和闭合符号长度都 >= 2,则是加强的强调,否则就是强调
- 在开始符号对应的文本节点之后,相应的插入一个强调或加强的强调节点
- 在分隔符栈中移除开始符号和闭合符号中间所有的分隔符
- 从开始和闭合文本节点中删除1(强调)或2(加强的强调)分隔符。 如果它们因此变为空,则删除它们并删除分隔符堆栈的相应元素。 如果关闭节点被移除,则将
current_position
重置为堆栈中的下一个元素
- 如果没有找到:
- 将
openers_bottom
设置为current_position
之前的元素。(我们知道这种闭合符号并没有对应的开始符号,所以这对之后的搜索设置了一个下限。) - 如果
current_position
处的闭合符号不是潜在的开始符号,则将其从分隔符堆栈中移除(因为我们知道它也不能作为闭合符号) - 将
current_position
推进到堆栈中的下一个元素
- 将
完成之后,我们从分隔符堆栈中删除stack_bottom
上面的所有分隔符。