为.net-IL或字节码编写编译器?

为.net-IL或字节码编写编译器?,.net,compiler-construction,cil,.net,Compiler Construction,Cil,我目前正在深入研究.net的内部工作机制,也就是IL。作为练习,我想为.net构建一个brainf..k编译器(是的,它们已经存在,但正如所说的,它是为了学习) 目前,我正在编写一些包含.il的文本文件,并使用ilasm编译它们,这是可行的。但我想知道我是否可以/应该更深入一层,直接编写字节码 我的“担心”是编译EXE时的Windows PE内容-而不是ilasm,我需要某种字节码链接器来获取我的MSIL/CIL字节码并为其生成PE内容 或者编译器是否“仅”将其语言编译为IL并执行ilasm?有

我目前正在深入研究.net的内部工作机制,也就是IL。作为练习,我想为.net构建一个brainf..k编译器(是的,它们已经存在,但正如所说的,它是为了学习)

目前,我正在编写一些包含.il的文本文件,并使用ilasm编译它们,这是可行的。但我想知道我是否可以/应该更深入一层,直接编写字节码

我的“担心”是编译EXE时的Windows PE内容-而不是ilasm,我需要某种字节码链接器来获取我的MSIL/CIL字节码并为其生成PE内容


或者编译器是否“仅”将其语言编译为IL并执行ilasm?有一个托管版本可以从我的编译器调用/嵌入吗?

有了新版本,我应该能够使用.Net类创建代码。我不确定它在多大程度上保护您不受实际IL/字节码的影响,因为这正是您试图学习的内容。

System.Reflection.Emit
提供了以静态类型的方式创建IL代码的工具,而无需使用IL生成和编译文本文件。

为什么不简单地使用api生成具有编译代码,然后将其保存到磁盘?应该比写出.IL文件容易得多

链接:

如果您想沿着这条路走下去,如果您在这里提出更具体的问题,您将得到大量关于如何定义动态程序集并将其保存到磁盘的示例

下面是一个例子:

using System;
using System.Reflection.Emit;
using System.Reflection;

namespace SO2598958
{
    class Program
    {
        static void Main()
        {
            AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(
                new AssemblyName("TestOutput"),
                AssemblyBuilderAccess.RunAndSave);

            ModuleBuilder mod = asm.DefineDynamicModule("TestOutput.exe",
                "TestOutput.exe");
            TypeBuilder type = mod.DefineType("Program", TypeAttributes.Class);

            MethodBuilder main = type.DefineMethod("Main",
                MethodAttributes.Public | MethodAttributes.Static);
            ILGenerator il = main.GetILGenerator();
            il.Emit(OpCodes.Ldstr, "Hello world!");
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine",
                BindingFlags.Public | BindingFlags.Static,
                null, new Type[] { typeof(String) }, null));
            il.Emit(OpCodes.Ret);

            type.CreateType();
            asm.SetEntryPoint(main);
            asm.Save("TestOutput.exe");
        }
    }
}
。使用解决方案直接链接到zip文件


如果您首先编译并运行此程序,它将在磁盘上生成一个新的exe文件,称为TestOutput,然后您可以执行该文件,以便在控制台上打印“Hello World!”。

如果我正确理解了您的问题,您至少会违反可移植性,直接实现jitting。把这些东西留给.NET、Mono或其他团队。所以我认为你不应该。但是关于你问题中的“可能”部分——我认为你可以跳过IL,编译成你想要的任何东西(据我所知,MonoTouch、MonoDroid等可以做到这一点): 来自维基百科

与Mono应用程序不同,MonoTouch“应用程序”被编译成专门针对苹果iPhone的机器代码


出于您的目的,Reflection.Emit将更加直截了当,但您可能也希望查看CodePlex上的项目

以下是该项目的项目页面摘要:

微软研究院通用编译器 基础设施(CCI)是一组 库和应用程序 编程接口(API) 支持一些功能 这是编译器和 相关编程工具

CCI元数据API允许 应用程序,以有效地分析或 修改.NET程序集、模块和 调试(PDB)文件。CCI元数据 支持.NET的功能 制度、反思与创新 System.Reflection.Emit API,但带有 更好的性能。它也 提供附加功能 在两个.NET API中都不可用


在编写.net编译器(ILGenerator、元数据帮助程序等)所需的所有其他东西中,该项目有一个PeWriter/PeReader。

您可以在那里查看:

您可以在那里查看非常简单的.net编译器:


不,我不想编写自己的.net运行时(但:),只是一个源代码->.net编译器。完全忘记了Reflection.Emit。如果我理解正确,我可以使用它和AssemblyBuilder编写完整的编译器?我相信IronPython的初始实现就是这样制作的。如果你指的是SO2598958名称空间,那只是我为答案创建解决方案并将其提交到我的存储库这一事实的产物,因此,很容易找到问题的正确文件夹。我所有的StackOverflow答案,我已经产生了一些代码,我想保留在这里:请注意,Reflection.Emit API并没有涵盖所有可能的codegen情况,对于其他一些情况,即使可能,它也很笨拙。对于BF编译器来说,这绝对足够好了,但我知道的“严肃”语言的编译器几乎都使用了其他东西-因此您可能想以此作为提示。
Reflection.Emit
的一些特定限制是什么?什么样的事情它不能做?有类似功能的替代方案吗?请注意,如果输出PE,您实际上不需要生成任何实际的本机代码-您需要生成CLI规范定义的PE头,其中包括一些本机可执行位,但它们是完全预定义的-它只是一个调用_CorExeMain的存根-因此您可以生成一次,并在编译器中将其视为不透明的字节序列。