grammar = - ( d:definition { setInTopNamespace(d.name, d.expression); } ) + end-of-file definition = i:identifier ASSIGN e:expression SEMI? { Definition.new(name: i, expression: e); } expression = s:sequence !BAR { s; } | s1:sequence { s1 = Alternation.new().push(s1); } ( BAR s2:sequence { s1.push(s2); } ) * { s1; } sequence = p:prefix { p = Sequence.new().push(p); } ( q:prefix { p.push(q); } ) * { p; } prefix = AND a:action { ParseTimeAction.new(action: a); } | ( AND s:suffix { And.new(expression: s); } | NOT s:suffix { Not.new(expression: s); } | s:suffix { s; } ) suffix = p:primary ( QUERY { p = Optional.new(expression: p); } | STAR { p = Star.new(expression: p); } | PLUS { p = Plus.new(expression: p); } ) ? { p; } primary = i1:identifier COLON i2:ruleCall !ASSIGN { Assignment.new(name: i1, rule: i2); } | i:ruleCall !ASSIGN { i; } | LPAREN e:expression RPAREN { e; } | l:literal { l; } | c:class { c; } | DOT { Dot.new(); } | a:action { a; } | BEGIN { Begin.new(); } | END { End.new(); } identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { intern(yytext); } ruleCall = n:identifier CCOLON r:identifier { NamespacedRuleCall.new(namespace: n, name: r); } | i:identifier { RuleCall.new(name: i); } literal = ['] < ( !['] char )* > ['] - { StringLiteral.new(string: yytext); } | ["] < ( !["] char )* > ["] - { StringLiteral.new(string: yytext); } class = '[' < ( !']' range )* > ']' - { CharacterClass.new(value: yytext); } range = char '-' char | char char = '\\' [abefnrtv'"\[\]\\] | '\\' [0-3][0-7][0-7] | '\\' [0-7][0-7]? | !'\\' . action = m:metaLanguage::block - { Action.new(parseTree: m); } - = ( space | comment )* space = ' ' | '\t' | end-of-line comment = '#' ( !end-of-line . )* end-of-line end-of-line = '\r\n' | '\n' | '\r' end-of-file = !. BAR = '|' - NOT = '!' - QUERY = '?' - BEGIN = '<' - END = '>' - SEMI = ";" - CCOLON = "::" - LPAREN = "(" - RPAREN = ")" - ASSIGN = "=" ![=] - AND = "&" ![&=] - PLUS = "+" ![+=] - STAR = "*" ![=] - DOT = "." ![.] - COLON = ":" ![:] -