(* wmap Language Specification *) (* Top-level structure *) program = { line } ; line = ( entity line_ending ) | ( ignored_line line_ending ) | line_ending ; entity = component | dependency | note | stage | group | inertia | evolution ; ignored_line = ? any sequence of tokens that doesn't match entity grammar ? ; (* Entities *) component = component_label position [ shape ] ; dependency = component_label dependency_type component_label ; note = case_insensitive("[Note]") position text ; stage = "[" stage_number "]" real_number ; group = case_insensitive("[Group]") component_label { "," component_label } ; inertia = case_insensitive("[Inertia]") component_label ; evolution = case_insensitive("[Evolution]") component_label sign real_number ; (* Component definitions *) position = "(" real_number "," real_number ")" ; shape = "[" shape_label "]" ; dependency_type = "--" | "->" ; sign = "+" | "-" ; (* Terminal symbols *) component_label = preserved_case( { character - ( "-" | "+" | "," | "[" | "]" | "(" | ")" | line_ending ) } ) ; text = preserved_case( { character - line_ending } ) ; real_number = [ digit ] { digit } [ "." { digit } ] | "." digit { digit } ; stage_number = case_insensitive( "i" | "ii" | "iii" | "iv" ) ; shape_label = case_insensitive( "x" | "square" | "triangle" | "circle" ) ; (* Lexical elements *) character = ? any Unicode character ? ; digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; line_ending = lf | crlf | cr ; lf = ? U+000A (Line Feed) ? ; cr = ? U+000D (Carriage Return) ? ; crlf = cr lf ; (* Lexical rules *) case_insensitive(x) = ? case-insensitive match of x ? ; preserved_case(x) = ? case-insensitive match of x, preserving original case for display ? ; (* Notes *) (* - Keywords and shape labels are case-insensitive *) (* - Component labels are case-insensitive for matching but preserve original case *) (* - Text content preserves original case *) (* - Whitespace (except line endings) may appear between any tokens *) (* - Each line contains exactly one entity *) (* - Invalid lines should be ignored *) (* - Line endings support Unix (LF), Windows (CRLF), and classic Mac (CR) formats *) (* - CRLF is treated as a single line ending, not separate CR and LF *)