GrammarWML

From The Battle for Wesnoth Wiki
Revision as of 22:49, 10 August 2016 by Celtic Minstrel (talk | contribs) (Rough draft of WML grammar)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

This page contains a formal grammar of the WML data language and preprocessor. It does not attempt to capture any of the ways that the Wesnoth engine may interpret a string, such as WML variable substitution. It also doesn't fully capture the potential consequences of macros, for example the use of unbalanced WML tags. The syntax used is regular-expression-like, with the following conventions:

  • Literal values are enclosed in either 'single quotes' or "double quotes".
  • Square brackets enclose character classes, with initial ^ inverting them
  • Whitespace within an expression (unless quoted) is used only for readability or to separate non-terminals
  • The meta-characters * + ? | have the same meaning as is typical in regular expressions
  • The sequence <tab> represents a tab character, and <nl> represents an end-of-line character or character sequence
  • Multiple definitions of a non-terminal are equivalent to alternation (ie, x:=4 and x:=7 combine to produce x:=4|7)
ws := ' ' | <tab>
ws_eol := whitespace* comment? <nl>
id := [a-zA-Z0-9_]+
wml_document := (preprocessor_statement | wml_attribute | wml_tag | macro_inclusion | ws* ws_eol)*
wml_attribute := ws* wml_key_sequence ws* '=' ws* wml_attribute_value ws_eol
wml_key_sequence := id (ws* ',' ws* id)*
wml_attribute_value := (text | ('_' ws*)? string) (ws* '+' ws_eol wml_attribute_value)
text := ([^ <tab>+"]+ ws*)*
string := '"' ([^"] | '""')* '"'
wml_tag := ws* '[' '+'? id ']' ws_eol wml_document ws* '[' '/' id ']'
comment := '#' [^<nl>]* <nl>
preprocessor_statement := macro_definition | ifdef_block | ifhave_block | ifver_block | line_preproc
line_preproc := '#undef' ws+ [^ <tab>]+ ws_eol | '#' ('warning' | 'error') ws+ [^<nl>]* ws_eol
macro_definition := '#define' (ws+ [^ <tab>]+)+ ws_eol anything '#enddef'
ifdef_block := '#ifdef' ws+ [^ <tab>]+ ws_eol anything ws_eol else_block? '#endif'
ifhave_block := '#ifhave' ws+ [^<nl>]+ ws_eol anything ws_eol else_block? '#endif'
ifver_block := '#ifver' ws+ comparison_expr ws_eol anything ws_eol else_block? '#endif'
else_block := '#else' ws_eol anything
macro_inclusion := '{' anything '}'