[ad_1]
Saya membuat kompiler DFA kecil yang merender langsung ke rakitan menggunakan System.Reflection.Emit
Perhatikan bahwa di bawah ini ada definisi FALIB. Ini akan selalu ditentukan ketika kompiler digunakan.
Kode IL saya seharusnya mengimplementasikan versi konkretnya
#if FALIB public #endif abstract partial class FARunner { protected abstract int MatchImpl(LexContext lc); protected abstract FAMatch SearchImpl(LexContext lc); /// <summary> /// Searches through text for the next occurance of a pattern matchable by this machine /// </summary> /// <param name="lc">The <see cref="LexContext"/> with the text to search</param> /// <returns>A series of <see cref="FAMatch"/> instances with the matches</returns> public IEnumerable<FAMatch> Search(LexContext lc) { while(lc.Current!=LexContext.EndOfInput) { yield return SearchImpl(lc); } } /// <summary> /// Indicates whether this machine will match the indicated text /// </summary> /// <param name="lc">A <see cref="LexContext"/> containing the text</param> /// <returns>The accept symbol if matched, otherwise -1.</returns> public int Match(LexContext lc) { return MatchImpl(lc); } /// <summary> /// Searches through text for the next occurance of a pattern matchable by this machine /// </summary> /// <param name="@string">The <see cref="IEnumerable{char}"/> with the text to search</param> /// <returns>A series of <see cref="FAMatch"/> instances with the matches</returns> public IEnumerable<FAMatch> Search(IEnumerable<char> @string) { foreach (var match in Search(LexContext.Create(@string))) { yield return match; } } /// <summary> /// Searches through text for the next occurance of a pattern matchable by this machine /// </summary> /// <param name="reader">The <see cref="TextReader"/> with the text to search</param> /// <returns>A series of <see cref="FAMatch"/> instances with the matches</returns> public IEnumerable<FAMatch> Search(TextReader reader) { foreach (var match in Search(LexContext.CreateFrom(reader))) { yield return match; } } /// <summary> /// Indicates whether this machine will match the indicated text /// </summary> /// <param name="text">The text</param> /// <returns>True if the passed in text was a match, otherwise false.</returns> public int Match(IEnumerable<char> text) { return Match(LexContext.Create(text)); } }
Tinggal mengisi SearchImpl dan MatchImpl dengan metode konkrit, yang sudah saya lakukan walaupun saat ini tidak diterapkan.
Masalah yang saya alami adalah ini – metode MatchImpl memanggil dengan baik.
Metode SearchImpl – aneh sekali. Itu tidak hanya tidak dipanggil, begitu pula metode apa pun yang mendelegasikannya. Saya tidak mendapatkan kesalahan, kompiler dilempar atau runtime. Itu diam-diam gagal ketika saya mencoba meneleponnya.
Satu-satunya hal yang dapat saya pikirkan adalah sesuatu tentang tipe pengembalian saya menjadi sebuah struct. Itulah satu-satunya perbedaan yang bisa saya lihat di sini – itu dan namanya.
Apa yang saya coba:
public static partial class FACompiler { public static FARunner Compile(this FA fa, IProgress<int> progress = null) { if (fa == null) throw new ArgumentNullException(nameof(fa)); fa = fa.ToDfa(progress); var name = "FARunner" + fa.GetHashCode(); var asmName = new AssemblyName(name); var asm = Thread.GetDomain().DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run); ModuleBuilder mod = asm.DefineDynamicModule("M"+name); TypeBuilder type = mod.DefineType(name, TypeAttributes.Public | TypeAttributes.Sealed, typeof(FARunner)); Type[] paramTypes = new Type[] { typeof(LexContext) }; Type searchReturnType = typeof(FAMatch); MethodBuilder searchImpl = type.DefineMethod("SearchImpl", MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig, searchReturnType, paramTypes); ILGenerator searchGen = searchImpl.GetILGenerator(); searchGen.ThrowException(typeof(NotImplementedException)); MethodInfo searchImplBase = typeof(FARunner).GetMethod("SearchImpl",BindingFlags.NonPublic | BindingFlags.Instance); type.DefineMethodOverride(searchImpl, searchImplBase); Type matchReturnType = typeof(int); MethodBuilder match = type.DefineMethod("MatchImpl", MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig, matchReturnType, paramTypes); ILGenerator matchGen = match.GetILGenerator(); matchGen.ThrowException(typeof(NotImplementedException)); MethodInfo matchBase = typeof(FARunner).GetMethod("MatchImpl", BindingFlags.NonPublic | BindingFlags.Instance); type.DefineMethodOverride(match, matchBase); Type newType = type.CreateType(); return (FARunner)Activator.CreateInstance(newType); } }
Saya juga mencoba menambahkan baris-baris ini untuk menyesuaikan tumpukan jika saya perlu mengisinya bahkan jika terjadi lemparan:
LocalBuilder famatch = searchGen.DeclareLocal(typeof(FAMatch)); searchGen.Emit(OpCodes.Ldloca_S, famatch); searchGen.Emit(OpCodes.Initobj, typeof(FAMatch));
Saya mendapatkan hasil yang sama.
Solusi 1
Saya tidak mengerti mengapa, tetapi ketika saya mengambil hasil dari kelas FARunner saya dan mengimplementasikan enumerator saya secara langsung, semuanya berfungsi dengan baik.
Saya menutup ini sebagai terselesaikan meskipun saya bingung.
[ad_2]
コメント