static ReElement ParseSequence(ReParseContext context) { var choice = new List <ReElement>(); var sequence = new List <ReElement>(); var abort = false; while (!context.End && !abort) { switch (context.Current) { case '[': if (!context.MoveNext()) { ThrowUnexpectedEnd(); } sequence.Add(ParseCharSet(context)); if (context.End) { ThrowUnexpectedEnd(); } if (context.Current != ']') { ThrowUnexpectedChar(context); } context.MoveNext(); break; case '(': if (!context.MoveNext()) { ThrowUnexpectedEnd(); } sequence.Add(ParseSequence(context)); if (context.End) { ThrowUnexpectedEnd(); } if (context.Current != ')') { ThrowUnexpectedChar(context); } context.MoveNext(); break; case ')': abort = true; break; case '|': choice.Add(ReFactory.NewConcatenation(sequence)); sequence.Clear(); context.MoveNext(); break; case '.': sequence.Add(ReFactory.NewSingleton(CharSet.LineBody)); context.MoveNext(); break; case '?': if (sequence.Count == 0) { ThrowUnexpectedChar(context); } sequence[sequence.Count - 1] = ReFactory.NewRepetition(sequence[sequence.Count - 1], 0, 1); context.MoveNext(); break; case '+': if (sequence.Count == 0) { ThrowUnexpectedChar(context); } sequence[sequence.Count - 1] = ReFactory.NewRepetition(sequence[sequence.Count - 1], 1, null); context.MoveNext(); break; case '*': if (sequence.Count == 0) { ThrowUnexpectedChar(context); } sequence[sequence.Count - 1] = ReFactory.NewRepetition(sequence[sequence.Count - 1], 0, null); context.MoveNext(); break; case '{': if (sequence.Count == 0) { ThrowUnexpectedChar(context); } if (!context.MoveNext()) { ThrowUnexpectedEnd(); } sequence[sequence.Count - 1] = ParseRepitition(sequence[sequence.Count - 1], context); if (context.Current != '}') { ThrowUnexpectedChar(context); } context.MoveNext(); break; case '\\': if (!context.MoveNext()) { ThrowUnexpectedEnd(); } sequence.Add(ReFactory.NewSingleton(CharSet.New(ParseEscapeSequence(context)))); break; default: sequence.Add(ReFactory.NewSingleton(CharSet.New(context.Current))); context.MoveNext(); break; } } choice.Add(ReFactory.NewConcatenation(sequence)); return(ReFactory.NewUnion(choice)); }
static ReElement ParseCharSet(ReParseContext context) { var ranges = new List <CharRange>(); var invert = false; if (context.Current == '^') { invert = true; if (!context.MoveNext()) { ThrowUnexpectedEnd(); } } if (context.Current == ']') { ranges.Add(new CharRange(']', ']')); if (!context.MoveNext()) { ThrowUnexpectedEnd(); } } var abort = false; while (!context.End && !abort) { switch (context.Current) { case ']': abort = true; break; case '-': if (ranges.Count == 0) { ranges.Add(new CharRange('-', '-')); } else { var from = ranges[ranges.Count - 1].To; if (!context.MoveNext()) { ThrowUnexpectedEnd(); } var to = context.Current; if (to == ']') { ranges.Add(new CharRange('-', '-')); } else { if (!context.MoveNext()) { ThrowUnexpectedEnd(); } if (to == '\\') { to = ParseEscapeSequence(context); if (context.End) { ThrowUnexpectedEnd(); } } if (to < from) { ThrowBrokenCharRange(from, to); } ranges.Add(new CharRange(from, to)); } } break; case '\\': if (!context.MoveNext()) { ThrowUnexpectedEnd(); } var c = ParseEscapeSequence(context); ranges.Add(new CharRange(c, c)); break; default: ranges.Add(new CharRange(context.Current, context.Current)); if (!context.MoveNext()) { ThrowUnexpectedEnd(); } break; } } var set = CharSet.New(ranges.ToArray()); if (invert) { set = CharSet.Universal.Subtract(set); } return(ReFactory.NewSingleton(set)); }