(* Markdown EBNF Grammar *) document = { block } ; block = heading | horizontal_rule | code_block | quote_block | list | table | paragraph | blank_line ; (* Headings *) heading = atx_heading | setext_heading ; atx_heading = "#" { "#" } [ " " ] inline_text newline ; setext_heading = inline_text newline ( ( "=" { "=" } ) | ( "-" { "-" } ) ) newline ; (* Horizontal Rule *) horizontal_rule = ( ( "*" [ " " ] "*" [ " " ] "*" { [ " " ] "*" } ) | ( "-" [ " " ] "-" [ " " ] "-" { [ " " ] "-" } ) | ( "_" [ " " ] "_" [ " " ] "_" { [ " " ] "_" } ) ) newline ; (* Code Blocks *) code_block = fenced_code_block | indented_code_block ; fenced_code_block = "```" [ language_identifier ] newline { code_line } "```" newline ; indented_code_block = { " " code_line } ; code_line = { character - newline } newline ; language_identifier = { letter | digit | "-" | "+" } ; (* Quote Blocks *) quote_block = { ">" [ " " ] ( inline_text | "" ) newline } ; (* Lists *) list = unordered_list | ordered_list ; unordered_list = { unordered_list_item } ; ordered_list = { ordered_list_item } ; unordered_list_item = [ " " { " " } ] ( "*" | "+" | "-" ) " " inline_text newline { continuation_line } ; ordered_list_item = [ " " { " " } ] digit { digit } "." " " inline_text newline { continuation_line } ; continuation_line = " " inline_text newline ; (* Tables *) table = table_header table_separator { table_row } ; table_header = "|" { table_cell "|" } newline ; table_separator = "|" { table_align_spec "|" } newline ; table_row = "|" { table_cell "|" } newline ; table_cell = { character - ( "|" | newline ) } ; table_align_spec = [ ":" ] "-" { "-" } [ ":" ] ; (* Paragraphs *) paragraph = inline_text { newline inline_text } newline ; (* Inline Elements *) inline_text = { inline_element } ; inline_element = emphasis | strong | code_span | link | image | autolink | line_break | plain_text ; emphasis = ( "*" non_asterisk_text "*" ) | ( "_" non_underscore_text "_" ) ; strong = ( "**" non_asterisk_text "**" ) | ( "__" non_underscore_text "__" ) ; code_span = "`" { "`" } non_backtick_text { "`" } "`" ; link = "[" link_text "]" "(" link_url [ " " link_title ] ")" ; image = "!" "[" alt_text "]" "(" image_url [ " " image_title ] ")" ; autolink = "<" ( url | email ) ">" ; line_break = " " newline | "\\" newline ; (* Text Content *) plain_text = { character - special_char } ; non_asterisk_text = { character - "*" } ; non_underscore_text = { character - "_" } ; non_backtick_text = { character - "`" } ; link_text = { character - ( "[" | "]" ) } ; alt_text = { character - ( "[" | "]" ) } ; link_url = { character - ( "(" | ")" | " " ) } ; image_url = { character - ( "(" | ")" | " " ) } ; link_title = quote_string ; image_title = quote_string ; quote_string = ( '"' { character - '"' } '"' ) | ( "'" { character - "'" } "'" ) ; url = "http" [ "s" ] "://" { character - ">" } ; email = { character - ( "@" | ">" ) } "@" { character - ">" } ; (* Utilities *) blank_line = newline ; special_char = "*" | "_" | "`" | "[" | "]" | "(" | ")" | "#" | ">" | "|" | "!" | "\\" ; newline = "\n" | "\r\n" ; character = letter | digit | symbol | " " ; letter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" ; digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; symbol = "!" | "@" | "#" | "$" | "%" | "^" | "&" | "*" | "(" | ")" | "-" | "_" | "=" | "+" | "[" | "]" | "{" | "}" | "\\" | "|" | ";" | ":" | "'" | '"' | "," | "." | "<" | ">" | "/" | "?" | "~" | "`" ;