Mercurial > pub > ImplabNet
comparison Implab/Formats/Grammar.cs @ 177:a0ff6a0e9c44 ref20160224
refactoring
| author | cin | 
|---|---|
| date | Wed, 23 Mar 2016 01:42:00 +0300 | 
| parents | |
| children | d5c5db0335ee | 
   comparison
  equal
  deleted
  inserted
  replaced
| 176:0c3c69fe225b | 177:a0ff6a0e9c44 | 
|---|---|
| 1 using Implab; | |
| 2 using System; | |
| 3 using System.Collections.Generic; | |
| 4 using System.Linq; | |
| 5 using Implab.Automaton; | |
| 6 using Implab.Automaton.RegularExpressions; | |
| 7 | |
| 8 namespace Implab.Formats { | |
| 9 /// <summary> | |
| 10 /// Базовый абстрактный класс. Грамматика, позволяет формулировать выражения над алфавитом типа <c>char</c>. | |
| 11 /// </summary> | |
| 12 public abstract class Grammar<TSymbol, TTag> { | |
| 13 | |
| 14 protected abstract IAlphabetBuilder<TSymbol> AlphabetBuilder { | |
| 15 get; | |
| 16 } | |
| 17 | |
| 18 protected SymbolToken<TTag> UnclassifiedToken() { | |
| 19 return new SymbolToken<TTag>(DFAConst.UNCLASSIFIED_INPUT); | |
| 20 } | |
| 21 | |
| 22 protected void DefineAlphabet(IEnumerable<TSymbol> alphabet) { | |
| 23 Safe.ArgumentNotNull(alphabet, "alphabet"); | |
| 24 | |
| 25 foreach (var ch in alphabet) | |
| 26 AlphabetBuilder.DefineSymbol(ch); | |
| 27 } | |
| 28 | |
| 29 protected Token<TTag> SymbolToken(TSymbol symbol) { | |
| 30 return Token<TTag>.New(TranslateOrAdd(symbol)); | |
| 31 } | |
| 32 | |
| 33 protected Token<TTag> SymbolToken(IEnumerable<TSymbol> symbols) { | |
| 34 Safe.ArgumentNotNull(symbols, "symbols"); | |
| 35 | |
| 36 return Token<TTag>.New(TranslateOrAdd(symbols).ToArray()); | |
| 37 } | |
| 38 | |
| 39 protected Token<TTag> SymbolSetToken(params TSymbol[] set) { | |
| 40 return SymbolToken(set); | |
| 41 } | |
| 42 | |
| 43 int TranslateOrAdd(TSymbol ch) { | |
| 44 var t = AlphabetBuilder.Translate(ch); | |
| 45 if (t == DFAConst.UNCLASSIFIED_INPUT) | |
| 46 t = AlphabetBuilder.DefineSymbol(ch); | |
| 47 return t; | |
| 48 } | |
| 49 | |
| 50 IEnumerable<int> TranslateOrAdd(IEnumerable<TSymbol> symbols) { | |
| 51 return symbols.Distinct().Select(TranslateOrAdd); | |
| 52 } | |
| 53 | |
| 54 int TranslateOrDie(TSymbol ch) { | |
| 55 var t = AlphabetBuilder.Translate(ch); | |
| 56 if (t == DFAConst.UNCLASSIFIED_INPUT) | |
| 57 throw new ApplicationException(String.Format("Symbol '{0}' is UNCLASSIFIED", ch)); | |
| 58 return t; | |
| 59 } | |
| 60 | |
| 61 IEnumerable<int> TranslateOrDie(IEnumerable<TSymbol> symbols) { | |
| 62 return symbols.Distinct().Select(TranslateOrDie); | |
| 63 } | |
| 64 | |
| 65 protected Token<TTag> SymbolTokenExcept(IEnumerable<TSymbol> symbols) { | |
| 66 Safe.ArgumentNotNull(symbols, "symbols"); | |
| 67 | |
| 68 return Token<TTag>.New( Enumerable.Range(0, AlphabetBuilder.Count).Except(TranslateOrDie(symbols)).ToArray() ); | |
| 69 } | |
| 70 | |
| 71 protected abstract IndexedAlphabetBase<TSymbol> CreateAlphabet(); | |
| 72 | |
| 73 protected ScannerContext<TTag> BuildScannerContext(Token<TTag> regexp) { | |
| 74 | |
| 75 var dfa = new RegularDFA<TSymbol, TTag>(AlphabetBuilder); | |
| 76 | |
| 77 var visitor = new RegularExpressionVisitor<TTag>(); | |
| 78 regexp.Accept( visitor ); | |
| 79 | |
| 80 visitor.BuildDFA(dfa); | |
| 81 | |
| 82 if (dfa.IsFinalState(dfa.InitialState)) | |
| 83 throw new ApplicationException("The specified language contains empty token"); | |
| 84 | |
| 85 var ab = CreateAlphabet(); | |
| 86 var optimal = dfa.Optimize(ab); | |
| 87 | |
| 88 return new ScannerContext<TTag>( | |
| 89 optimal.CreateTransitionTable(), | |
| 90 optimal.CreateFinalStateTable(), | |
| 91 optimal.CreateTagTable(), | |
| 92 optimal.InitialState, | |
| 93 ab.GetTranslationMap() | |
| 94 ); | |
| 95 } | |
| 96 | |
| 97 } | |
| 98 | |
| 99 | |
| 100 } | 
