写一个 马克down translator 玩?

C语言,那就是说是哪些来头造成差其余解析器之间时有暴发的结果会分裂?我相信广大人都早已明白了
i++ * i++ * i++ 这些经典的 C语言的标题了
(要是不晓得可以看这里)

很早以前自己曾用 js 写过一个简陋的 马克down
translator,它是由若干的正则合作局地流水线控制语句来落成的。如今见到众多有关
马克down 语法的篇章,我就又回头看了下那一个代码,于是决定选用 swift
重写一个。

深谙 HTML 语法的同窗很简单就会发觉最终一行的不当。

在自家最初接触 马克down
的时候,我发现许多解析器之间的结果存在差距,比如有诸如此类的文书:

XEBNF 是自身自己的 extend
BNF
,哈哈。使用
XEBNF 是因为 BNF 的 ::= 书写太费事,而 ABNF 又从未 EBNF 中的 exception
- 功用。我还写了一个 Atom 的 Syntax 来支撑
XBNF,于是它们看起来像是那样:

答案是肯定的。

幸好出于 马克down 的小编没有付诸完整的语法定义,导致在遇见一些 Undefined
Behavior 时,每个 translator
的作者必须团结去想一个恰当的输出结果,那样就导致了各家的输出会有一部分进出。可能小编也没悟出
马克down 会流行到这几个程度呢,哈。

相信您会找到不只一个 马克down
解析器,那么它们对于地方的文件会时有发生差别的辨析结果吧?

这一次重写我决定装出点样子,代码中将不应用正则,在解析了 马克down
文本之后,首先生成一个 Tree,然后才是根据 Tree 中的内容暴发 HTML。

马克down 的产出就是为了让文本内容变得易读易写,所以借助 马克down
的语法格则,固然在纯文本情势下也足以获得相比好的开卷效果。但是,很多景况下,大家会将
马克down 解析成 HTML,合营 CSS 来获得越来越鲜艳夺目标翻阅感受。

> ## This is an H2 in a blockquote
> > nested blockquote
> H1
> ====
# header
===

可望得以给想要自己出手写一个 马克down translator 的同班一点支援吧

上面就是自身眼前小结出的语法,如今唯有 block
元素,因为我先写的块元素的解析:

Char                          = [#x0000-#xD7FF] | [#xE000-#x10FFFF]
SP                            = #x0020
HTAB                          = #x0009
CR                            = #x000D
LF                            = #x000A
CRLF                          = CR LF
NL                            = CR | LF | CRLF
WSP                           = HTAB | SP
LWSP                          = NL | WSP
DIGIT                         = [#x0030-#x0039]

; md
md                            = md-block*

; md-block
md-block                      = paragraph | header | blockquote | list | codeblock

; paragraph
paragraph-begin               = SP{0,3} ( Char - ( LWSP | ">" | "*" | "#" ) )
paragraph-content             = ( ( Char - NL ) NL? )+
paragraph-end                 = NL{2} | NL ( Char - ( ">" | "*" | "#" ) )
paragraph                     = paragraph-begin paragraph-content paragraph-end

; header-setext
header-setext-begin           = SP{0,3} ( Char - ( LWSP | ">" | "*" | "# ) )
header-setext-content         = Char - NL
header-setext-end             = NL ( "=" | "-" )+
header-setext                 = header-setext-begin header-setext-content header-setext-end

; header-atx
header-atx-begin              = SP{0,3} "#"+ WSP* ( Char - LWSP )
header-atx-content            = Char - NL
header-atx-end                = "#"* NL
header-atx                    = header-atx-begin header-atx-content header-atx-end

; header
header                        = header-setext | header-atx

; blockquote
blockquote-begin              = SP{0,3} ">"
blockquote-content            = ( header | paragraph | blockquote | list | codeblock )*
blockquote-end                = NL{2} ( Char - ">" )

; list-ul-item
list-ul-item-begin            = SP{0,3} "*" WSP
list-ul-item-content          = ( paragraph | blockquote | list | codeblock )*
list-ul-item-end              = NL{2} ( Char - SP )
list-ul-item                  = list-ul-item-begin list-ul-item-content list-ul-item-end

; list-ul
list-ul                       = list-ul-item+

; list-ol-item
list-ol-item-begin            = SP{0,3} DIGIT "." WSP
list-ol-item-content          = ( paragraph | blockquote | list | codeblock )*
list-ol-item-end              = NL{2} ( Char - SP )
list-ol-item                  = list-ol-item+

; list
list                          = list-ul | list-ol

; codeblock-md
codeblock-md-begin            = ( SP{4} | HTAB ) WSP* ( Char - WSP )
codeblock-md-content          = Char* - codeblock-md-end
codeblock-md-end              = NL SP{0,3} ( Char - WSP )
codeblock-md                  = codeblock-md-begin codeblock-md-content codeblock-md-end

; codeblock-ext
codeblock-ext-begin           = SP{0,3} "`"{3} ( Char - NL ) NL
codeblock-ext-content         = Char* - codeblock-ext-end
codeblock-ext-end             = NL "`"{3} ( Char - NL ) NL
codeblock-ext                 = codeblock-ext-begin codeblock-ext-content codeblock-ext-end

; codeblock
codeblock                     = codeblock-md | codeblock-ext

; html-element
html-element-attr             = Char+ - LWSP
html-element-name             = Char+ - LWSP

html-void-element             = SP{0,3} "<"html-element-name WSP* "/>" NL

html-normal-element-start     = SP{0,3} "<"html-element-name (WSP+ html-element-attr)* WSP* ">"
html-normal-element-content   = Char* - html-normal-element-end
html-normal-element-end       = "</"html-element-name WSP* ">" NL
html-normal-element           = html-normal-element-start html-normal-element-content html-normal-element-end

html-element                  = html-empty-element | html-void-element
<blockquote>
  <h2>This is an H2 in a blockquote</h2>

<blockquote>
  <p>nested blockquote</p>

<h1>H1</h1>
</blockquote>

<p></blockquote></p>

自然在写往日,依然要分析下 马克down
语法,并不可能只是看看一些小例子,需求在 github 和其余多少个 马克down
编辑软件持续中试错,小结出语法,并选用 XEBNF 来讲述。

它会提交上面的结果:

科学,这就是 马克down 中的 Undefined Behavior,究其原因就是因为 马克down
的发明者并不曾给出 马克down
语法的完好定义,他只是在语法表明中举了一部分简易的例子,并附着了投机行使
Perl 写的
Translator。不幸的是那段代码已经年久失修,你能够很简单找出它的
bug,对于上面的公文:

Markdown
早在 2004
年就被发明出来,可以普及到前日的程度离不开它的发明者和持有应用它来创作的人

它的中央语法表达可以在其发明者的
Blog
中找到。马克down 的风靡一定水平上离不开 github 的进献,同时 github
也增加了 马克down 语法,使得它可以表明更为助长的情节。

有了语法之后,就可以早先写代码了,进程是很枯燥的,就是运用递归下落的方式,都是部分很机械的做事,代码在这里,相信会百折不挠写完吧樂