# LaTeX-Grammar for DHParser

# preamble
@ literalws  = right
@ whitespace = /[ \t]*(?:\n(?![ \t]*\n)[ \t]*)?/    # insignificant whitespace, including at most one linefeed
@ comment    = /%.*/                                # note: trailing linefeed is not part of the comment proper
@ reduction  = merge_treetops
@ disposable = /_\w+/
# @ disposable = _WSPC, _GAP, _LB, _PARSEP, _LETTERS, _NAME, _INTEGER, _FRAC,
#                _QUALIFIED, _TEXT_NOPAR, _TEXT, _block_content, _PATH, _PATHSEP,
#                _HASH, _COLON, _TAG, _inline_math_text, _has_block_start,
#                _block_environment, _known_environment, _text_element, _block_math,
#                _line_element, _inline_environment, _known_inline_env, _info_block,
#                _begin_inline_env, _end_inline_env, _command, _known_command,
#                _dmath_long_form, _dmath_short_form, _BACKSLASH, _structure_name,
#                _env_name
@ drop       = strings, backticked, whitespace, regexps, _WSPC, _GAP, _PARSEP, _LB,
               _has_block_start, _BACKSLASH, _structure_name, _env_name

########################################################################
#
#: outer document structure
#
########################################################################

latexdoc       = preamble §document
preamble       = { [_WSPC] _command }+

document       = [_WSPC] "\begin{document}"
                 §frontpages
                 (Chapters | Sections)
                 [Bibliography] [Index] [_WSPC]
                 "\end{document}" [_WSPC] EOF
frontpages     = sequence


#######################################################################
#
#: document structure
#
#######################################################################

Chapters       = { [_WSPC] Chapter }+
Chapter        = `\chapter` [hide_from_toc] heading { sequence | Sections | Paragraphs }

Sections       = { [_WSPC] Section }+
Section        = `\section` [hide_from_toc] heading { sequence | SubSections | Paragraphs }

SubSections    = { [_WSPC] SubSection }+
SubSection     = `\subsection` [hide_from_toc] heading { sequence | SubSubSections | Paragraphs }

SubSubSections = { [_WSPC] SubSubSection }+
SubSubSection  = `\subsubsection` [hide_from_toc] heading { sequence | Paragraphs }

hide_from_toc  = "*"

Paragraphs     = { [_WSPC] Paragraph  }+
Paragraph      = "\paragraph" heading { sequence | SubParagraphs }

SubParagraphs  = { [_WSPC] SubParagraph }+
SubParagraph   = "\subparagraph" heading [ sequence ]

Bibliography   = [_WSPC] "\bibliography" heading
Index          = [_WSPC] "\printindex"

heading        = block


#######################################################################
#
#: document content
#
#######################################################################


#### block environments ####

_block_environment  = &_has_block_start _known_environment | generic_block
  _has_block_start  = `\begin{` | `\[`
_known_environment   = itemize | enumerate | description | figure | tabular | quotation
                    | verbatim | math_block
math_block          = equation | eqnarray | displaymath
generic_block       = begin_generic_block { sequence | item } §end_generic_block
begin_generic_block = <-&_LB begin_environment
@ end_generic_block_error = '', "A block environment must be followed by a linefeed, not by: {1}"
end_generic_block   = end_environment § (LFF | ~ &`}`)

itemize             = "\begin{itemize}" _itemsequence §"\end{itemize}"
enumerate           = "\begin{enumerate}" _itemsequence §"\end{enumerate}"
description         = "\begin{description}" _itemsequence §"\end{description}"
  _itemsequence     = [_WSPC] { (item | _command) [_WSPC] }
@item_error         = '', '\item without proper content, found: {1}'
item                = "\item" [config] § sequence

figure              = "\begin{figure}" sequence §"\end{figure}"
quotation           = ("\begin{quotation}" sequence §"\end{quotation}")
                    | ("\begin{quote}" sequence §"\end{quote}")
verbatim            = "\begin{verbatim}" verbatim_text §"\end{verbatim}"
  verbatim_text     = /(?:(?!\\end{verbatim})[\\]?[^\\]*)*/

displaymath         = _dmath_long_form | _dmath_short_form
  _dmath_long_form  = `\begin{displaymath` [no_numbering] "}" § _block_math `\end{displaymath` [`*`] "}"
  _dmath_short_form = "\[" § _block_math "\]"
equation            = `\begin{equation` [no_numbering] "}" §_block_math `\end{equation` [`*`] "}"
eqnarray            = `\begin{eqnarray` [no_numbering] "}" §_block_math `\end{eqnarray` [`*`] "}"
  _block_math       = /(?:[^\\]*[\\]?(?!end\{(?:eqnarray|equation|displaymath)\*?\}|\])\s*)*/
no_numbering        = `*`

tabular             = "\begin{tabular}" tabular_config { tabular_row | _WSPC } §"\end{tabular}"
tabular_row         = (multicolumn | tabular_cell) { "&" (multicolumn | tabular_cell) }
                      ("\\" ( hline | { cline } ) [_PARSEP] | &`\end{tabular}`)
tabular_cell        = raisebox [S|_PARSEP] | { _line_element [S|_PARSEP] }
raisebox            = "\raisebox" rb_offset [rb_up] [rb_down] block
  rb_offset         = "{" number UNIT ~ "}"
  rb_up             = "[" number UNIT ~ "]"
  rb_down           = "[" number UNIT ~ "]"
tabular_config      = "{" { cfg_celltype [cfg_unit] | cfg_separator | / +/ }+ §"}"
  cfg_celltype      = /[lcrp]/
  cfg_unit          = `{` number UNIT `}`
  cfg_separator     = `|` | `!` block

#### paragraphs and sequences of paragraphs ####

block_of_paragraphs = "{" [sequence] §"}"
sequence            = [_WSPC] { (paragraph | _block_environment) [_PARSEP|S] }+
paragraph           = { !blockcmd _text_element [S] }+
_text_element       = _line_element | LINEFEED
_line_element       = text | _inline_environment | _command | block


#### inline enivronments ####

_inline_environment = _known_inline_env | generic_inline_env
_known_inline_env   = inline_math
generic_inline_env  = _begin_inline_env ~ paragraph !_PARSEP §_end_inline_env
_begin_inline_env   = (<-!_LB begin_environment) | (begin_environment !LFF)
_end_inline_env     = end_environment
                      ## (<-!_LB end_environment)   | (end_environment !LFF)  # ambiguity with generic_block when EOF
begin_environment   = /\\begin{/ §NAME /}/
end_environment     = /\\end{/ §::NAME /}/

inline_math         = _im_dollar | _im_bracket
  _im_dollar        = `$` § _inline_math_text `$`
  _im_bracket       = `\(` § _inline_math_text `\)`
_inline_math_text   = /[^$]*/

#### commands ####

_command             = _known_command | text_command | assignment | generic_command

_known_command      = citet | citep | footnote | includegraphics | caption
                    | multicolumn | hline | cline | documentclass | pdfinfo
                    | hypersetup | label | ref | href | url | item
text_command        = TXTCOMMAND | ESCAPED | BRACKETS
assignment          = !no_command CMDNAME "=" (number [UNIT] | block | CHARS)
generic_command     = !no_command CMDNAME { ~ (config | block) }
                    | `{` CMDNAME _block_content §`}`

citet               = "\citet" [config] block
citep               = ("\citep" | "\cite") [config] block
footnote            = "\footnote" block_of_paragraphs
includegraphics     = "\includegraphics" [ config ] block
caption             = "\caption" block
multicolumn         = "\multicolumn" "{" column_nr "}" tabular_config block_of_paragraphs
hline               = "\hline"
cline               = "\cline{" column_nr "-" column_nr "}"
  column_nr         = _INTEGER
documentclass       = "\documentclass" [ config ] block
pdfinfo             = "\pdfinfo" _info_block
hypersetup          = "\hypersetup" param_block
label               = "\label{" CHARS "}"
ref                 = ( "\ref{" | "\pageref{" ) CHARS "}"
url                 = "\url{" urlstring "}"
href                = "\href{" urlstring "}" block
  urlstring         = [protocol] { path } [target]
  protocol          = /\w+:\/\/(?!\*)/
  path              = _pth _PATHSEP
  target            = _pth { <-!/s?ptth/ _COLON _pth } [ ([_BACKSLASH] _HASH| <-!/s?ptth/ _COLON) _TAG ]
  _pth              = { _PATH | ESCAPED }+

#######################################################################
#
#: text
#
#######################################################################

block          = "{" _block_content §`}`
_block_content = [_PARSEP|S] { (_block_environment | _text_element | paragraph) [_PARSEP|S] }
# text           = {CHARS|special}+ { (S {CHARS|special}+ }
# text           = {LINE|special}+ { (S {LINE|special}+ }
text           = {_TEXT|special}+ { S  {_TEXT|special}+ }
  special      = `\-` | /\\/ esc_char   # reserved for characters that may appear in
               | UMLAUT | QUOTEMARK
  esc_char     = `,`                    # in the middle of a word but do not delimit words

no_command     = "\begin{" | "\end{" | _BACKSLASH _structure_name &`{`
blockcmd       = _BACKSLASH ( ( "begin{" | "end{" ) _env_name "}"
                           | _structure_name & `{` | `[` | `]`)

_env_name      = `enumerate` | `itemize` | `description` | `figure` | `quote`
               | `quotation` | `tabular` | `displaymath` [`*`]
               | `equation` [`*`] | `eqnarray` [`*`]
_structure_name = `subsection` | `section` | `chapter` | `subsubsection`
               | `paragraph` | `subparagraph` | `item`


#######################################################################
#
#: parameters
#
#######################################################################

config       = "[" § (parameters &"]" | cfg_text) "]"

param_block  = "{" [parameters] "}"
parameters   = (association | flag) { <-! _BACKSLASH "," (association | flag) }  [ WARN_Komma ]
association  = key~ "=" value~
flag         = _QUALIFIED | magnitude
key          = _QUALIFIED
value        = magnitude | _LETTERS | CMDNAME | param_block | block

_info_block  = "{" §{ info_assoc } "}"
info_assoc   = info_key ~ [ "(" §info_value ")" ]
info_key     = `/` _NAME
info_value   = _TEXT_NOPAR { S _TEXT_NOPAR }  # text without parentheses

magnitude    = number [UNIT]
number       = _INTEGER [_FRAC]
cfg_text     = { (~ text) | CMDNAME | SPECIAL | block }


#######################################################################
#
#: errors and warnings
#
#######################################################################

WARN_Komma = ","


#######################################################################
#
#: primitives
#
#######################################################################

CMDNAME    = /\\@?(?:(?![\d_])\w)+/~
TXTCOMMAND = /\\text\w+/
ESCAPED    = /\\(?:(?:[#%$&_\/{} \n])|(?:~\{\s*\}))/
UMLAUT     = /\\(?:(?:"[AOUaou])|(?:'[aeiou])|(?:`[aeiou])|(?:[\^][aeiou]))/
QUOTEMARK  = /"[`']?|``?|''?/
SPECIAL    = /[$&_\/\\\\]/
BRACKETS   = /[\[\]]/                       # left or right square bracket: [ ]
LINEFEED   = /[\\][\\]/

_QUALIFIED = IDENTIFIER { <-! _BACKSLASH /[:.-]/ IDENTIFIER }
IDENTIFIER = _NAME
NAME       = _NAME                          # captured! don't use without retrival
_NAME      = /(?!\d)\w+\*?/
_INTEGER   = /-?(?:(?:[1-9][0-9]+)|[0-9])/
_FRAC      = /\.[0-9]+/
UNIT       = /(?!\d)\w+/

_PATH      = /[\w=~?.,%&\[\]-]+/
_PATHSEP   = /\/(?!\*)/
_HASH      = `#`
_COLON     = `:`
_TAG       = /[\w=?.:\-%&\[\] \/]+/

_TEXT      = /(?:[^\\%$&\{\}\[\]\n'`"]+(?:\n(?![ \t]*\n))?)+/
_TEXT_NOPAR = /(?:[^\\%$&\{\}\[\]\(\)\n]+(?:\n(?![ \t]*\n))?)+/  # text without parnetheses
# LINE       = /[^\\%$&\{\}\[\]\n'`"]+/          # a line of text
CHARS      = /[^\\%$&\{\}\[\]\s\n'`"]+/        # some piece of text excluding whitespace,
                                            # linefeed and special characters
_LETTERS   = /\w+/
# LF         = NEW_LINE { COMMENT__ WHITESPACE__ } | EOF # linefeed but not an empty line
LFF        = NEW_LINE [ _WSPC ] | EOF       # at least one linefeed
S          = &/[% \t\n]/ !_GAP WSP_RE__     # significant whitespace
_PARSEP    = { WHITESPACE__ COMMENT__ } _GAP [_WSPC] # paragraph separator
_WSPC      = { COMMENT__ | /\s+/ }+         # arbitrary horizontal or vertical whitespace
_GAP       = /[ \t]*(?:\n[ \t]*)+\n/~       # at least one empty line, i.e.
                                            # [whitespace] linefeed [whitespace] linefeed
NEW_LINE   = /[ \t]*/ [COMMENT__] /\n/
_LB        = /\s*?\n|$/                     # backwards line break for Lookbehind-Operator
                                            # beginning of text marker '$' added for test code
_BACKSLASH  = /[\\]/

EOF        = /(?!.)/                        # End-Of-File
