# Treetop grammar for gabc (input format of Gregorio). # Compiled by Treetop emits GabcParser class.

grammar Gabc

rule score
  header
  header_delimiter
  body
  <ScoreNode>
end

# header ----------------------------

rule header
  ( header_field?
    inline_whitespace?
    comment?
    "\n" )*
    <HeaderNode>
end

rule inline_whitespace
  (" " / "\t")+
end

rule any_whitespace
  (inline_whitespace / "\n")+
end

rule header_field
  field_id
  ":"
  inline_whitespace?
  field_value
  ";" ..2
  <HeaderFieldNode>
end

rule field_id
  [\w-]+
end

rule field_value
  (
   [^;] /
   (";" !(inline_whitespace? comment? "\n"))
   )*
end

rule comment
  "%" !"%" [^\n]*
end

rule header_delimiter
  "%%\n"
end

# body ------------------------------

rule body
  any_whitespace?
  ( ( comment any_whitespace? ) /
    ( music_word any_whitespace? comment? any_whitespace? ) )*
  music_word?
  <BodyNode>
end

rule clef_standalone
  "(" clef ")"
end

rule clef
  clef_symbol bemol:"b"? line_number <ClefNode>
end

rule clef_symbol
  "c" / "f"
end

rule line_number
  [1-4]
end

rule music_word
  music_syllable+ <WordNode>
end

rule music_syllable
  lyrics:lyrics_syllable? music <SyllableNode>
end

rule lyrics_syllable
  word_character+
    ( any_whitespace
      word_character+
      )*
    any_whitespace?
end

rule word_character
  guillemets / special_word_character / formatted_characters / text_above_lines / regular_word_character
end

rule regular_word_character
  [^\(\n\t ] # anything but: opening parentheses, newline, tab, space
end

rule special_word_character
  "<sp>" (regular_word_character / parentheses)+ "</sp>"
end

# this rule doesn't handle tag mismatch.
# However, for purposes of gabc->lilypond convertor
# such an issue may be safely ignored.
rule formatted_characters
  "<" formatting_tag ">"
  ( regular_word_character / special_word_character / inline_whitespace / formatted_characters / parentheses )+
  "</" formatting_tag ">"
end

rule formatting_tag
  "b" / "i" / "sc" / "v"
end

rule text_above_lines
  "<alt>"
  ( regular_word_character / inline_whitespace )+
  "</alt>"
end

rule parentheses
  [\(\)]
end

rule guillemets
  "<<" / ">>"
end

rule music
  "(" notes? neumes? ")"
end

rule notes
  ( clef / guide / alteration / (note choral_sign? brace?) / space / custos / linebreak / divisio / macro / text_above_lines_in_music )+
end

rule note
  initio_debilis? note_pitch shape_modifiers? rhythmic_sign* accent?
  <NoteNode>
end

rule note_pitch
  simple_pitch / punctum_inclinatum_pitch
end

# used not only in notes
rule simple_pitch
  [a-m]
end

rule punctum_inclinatum_pitch
  [A-M]
end

rule initio_debilis
  "-"
end

rule shape_modifiers
  ( [oOVwWqR] / "v"+ / "s"+ / ([r] "0"? ![1-5]) )? [~<>]?
end

rule rhythmic_sign
  "." / ("'" above_below?) / ("_" episema_modifiers?)
end

rule above_below
  [01]
end

rule episema_modifiers
  [0-5] ..3
end

rule accent
  "r" [1-5]
end

rule space
  ( "!"? ( ("/" "/"?) / " " ) ) /
    "!"
end

rule linebreak
  [zZ]
end

rule custos
  "z0"
end

# ~ custos at the end of a score
rule guide
  simple_pitch "+"
end

rule alteration
  simple_pitch [xy\#]
end

rule divisio
  (( "," "_"? ) /
    "`" /
    ( ";" [1-6]? ) /
    ( ":" (":" / "'")? ))
  <DivisioNode>
end

rule choral_sign
  "[cs:" [^\]]+ "]"
end

rule brace
  "[o" "c"? "b" "a"? ":" [^\]]+ "]"
end

rule macro
  "[" [nge] "m" [0-9] "]"
end

rule text_above_lines_in_music
  "[alt:" [^\]]* "]"
end

rule neumes
  "|" [^\)]*
end

end