akrantiain2 by la. sozysozbot.
snoj:
Sentences = xs:(Sentence / Comment / Space)* { var ret = { define: {}, conversions: [], option: {} }; xs.forEach(function(x) { if (x === null ) return; if (x.define) ret.define[x.define.id] = x.define.values; if (x.conversion) ret.conversions.push(x.conversion); if (x.option) ret.option[x.option] = true; }); return ret; } Sentence = sent:(Conversion / Define / AtSignOption) _ ';'? { return sent; } Comment = '#' [^\n]* '\n'? { return null; } Space = [ \t\r\n\f\v] { return null; } String = '"' chars:([^\\"\n] / EscapeSequence)* '"' { return chars.join(''); } Slash = '/' chars:([^\\/\n] / EscapeSequence)* '/' { return chars.join(''); } EscapeSequence = '\\' char:('\\' / '"' / '/' / "'") { return char; } Identifier = $([A-Za-z] [A-Za-z0-9_]*) Define = id:Identifier _ '=' _ values:StringsSepByPipe { return { define: { id: id, values: values.map(function(x) { return x.join(""); }) }}; } Select = '^' { return { bound: true }; } / id:Identifier { return { id: id }; } / Strings / '(' xs:StringsSepByPipe ')' { return { or: xs.map(function(x) { return x.join(""); }) }; } Strings = head:String tail:(_ String)* { return [head].concat(tail.map(function(x) { return x[1]; })); } StringsSepByPipe = head:Strings tail:(_ '|' _ Strings)* { return [head].concat(tail.map(function(x) { return x[3]; })); } Conversion = lcond:NegSelect? _ selects:Selects _ rcond:NegSelect? _ '->' _ phonemes:Phonemes { if (lcond != null) { selects.unshift(lcond); } if (rcond != null) { selects.push(rcond); } return { conversion: { selects: selects, phonemes: phonemes }}; } NegSelect = '!' _ select:Select { return { not: select }; } Selects = head:Select tail:(_ Select)* { var xs = [head].concat(tail.map(function(x) { return x[1]; })); var ret= []; xs.forEach(function(x) { if (Array.isArray(x)) ret = ret.concat(x); else ret.push(x); }); return ret; } Phonemes = head:Phoneme tail:(_ Phoneme)* { return [head].concat(tail.map(function(x) { return x[1]; })); } Phoneme = '$' { return null; } / Slash AtSignOption = '@' _ id:Identifier { return { option: id }; } _ = [ \t\r\f\v]*