[ad_1]
我正在制作一个小型 DFA 编译器,它使用 System.Reflection.Emit 直接渲染到程序集
请注意,下面有一个 FALIB 定义。 当使用编译器时,它总是被定义。
我的 IL 代码应该实现这个的具体版本
#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)); } }
它只需要用具体方法填充 SearchImpl 和 MatchImpl ,我已经完成了,尽管它们目前抛出未实现的错误。
我遇到的麻烦是这个 – MatchImpl 方法调用得很好。
SearchImpl 方法——这很奇怪。 它不仅不会被调用,而且委托给它的任何方法也不会被调用。 我没有收到错误、编译器抛出或运行时错误。 当我尝试调用它时,它只是默默地失败了。
我唯一能想到的是我的返回类型是一个结构。 这是我能看到的唯一区别——好吧,还有名字。
我尝试过的:
C#
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); } }
我还尝试添加这些行来调整堆栈,以防万一即使在抛出异常时也需要填充堆栈:
C#
LocalBuilder famatch = searchGen.DeclareLocal(typeof(FAMatch)); searchGen.Emit(OpCodes.Ldloca_S, famatch); searchGen.Emit(OpCodes.Initobj, typeof(FAMatch));
我得到相同的结果。
解决方案1
我不明白为什么,但是当我从 FARunner 类中取出收益并手动实现我的枚举器时,一切都工作正常。
尽管我很困惑,但我还是把这个问题解决了。
[ad_2]
コメント