tags:

views:

465

answers:

7

I'm currently diving into the inner workings of .net, which means IL. As an exercise, I want to build a brainf..k compiler for .net (yes, they already exist, but as said it's for learning purposes).

For the moment I'm just writing some text files that contain .il and compile them with ilasm, which works. But I wonder if I could/should go one level deeper and write bytecode directly?

My "concern" is the Windows PE Stuff when compiling an EXE - instead of ilasm I would need some sort of Bytecode linker that would take my MSIL/CIL bytecode and generate the PE Stuff for it?

Or do compilers "only" compile their language to IL and execute ilasm? Is there a managed version of it that I can call/embed from my compiler?

A: 

With the new DLR one should be able to do code creation using .Net classes. I'm not sure how much it shields you from the actual IL/bytecode since this is what you are trying to learn.

Toad
+3  A: 

System.Reflection.Emit provides facilities to create IL code in a statically-typed way without having to generate and compile text files with IL.

Marcelo Cantos
+11  A: 

Why not simply use the Reflection.Emit api to produce a in-memory assembly with the compiled code and then save it to disk? Should be a lot easier than writing out .IL files.

Links:

If you want to go down this road, if you ask more specific questions here on SO you'll get plenty of example of how to define a dynamic assembly and save it to disk.

Here's an example:

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");
        }
    }
}

You can download the test solution file from here. Direct link to zip file with solution here.

If you first compile and run this program, it'll produce a new exe file on disk, called TestOutput, which you can then execute in order to have "Hello World!" printed on the console.

Lasse V. Karlsen
Completely forgot about Reflection.Emit. If I understand this correctly, I can write the complete compiler using it and AssemblyBuilder?
Michael Stum
I believe that was how the initial implementations of IronPython was made.
Brian Rasmussen
See my added example code which produces a new executable.
Lasse V. Karlsen
+1 for the namespace cleverness
Nir Levy
Lasse V. Karlsen
Note that Reflection.Emit APIs do not cover all possible codegen cases, and for some others it's clunky even when possible. It's definitely good enough for a BF compiler, but pretty much all compilers for "serious" languages that I'm aware of use something else - so you may want to take that as a hint.
Pavel Minaev
A: 

If i understood your question correctly, you will at the very least violate portability, by implementing jitting directly. Leave this stuff to .NET, Mono, Whatever teams. So i think you shouldn't. But about a 'could' part of your question - i think you can skip IL, and compile into whatever you want (as far as i know, MonoTouch, MonoDroid, etc do that): From Wikipedia

Unlike Mono applications MonoTouch "Apps" are compiled down to machine code targeted specifically at the Apple iPhone.

n535
No, I don't want to write my own .net Runtime (yet :)), just a Source Code -> .net Compiler.
Michael Stum
+1  A: 

Reflection.Emit is going to be more straight forward for your purposes, but you may want to look at the Common Compiler Infrastructure project on CodePlex too.

Here is the summary from the project page for that project:

Microsoft Research Common Compiler Infrastructure (CCI) is a set of libraries and an application programming interface (API) that supports some of the functionality that is common to compilers and related programming tools.

The CCI Metadata API allows applications to efficiently analyze or modify .NET assemblies, modules, and debugging (PDB) files. CCI Metadata supports the functionality of the .NET System.Reflection and System.Reflection.Emit APIs, but with much better performance. It also provides additional functionality that is not available in either .NET API.

That project has a PeWriter/PeReader among all the other things you would need to write a .net compiler (ILGenerator, Metadata helpers, etc.).

Jason Haley
A: 

You can look there: http://msdn.microsoft.com/es-es/library/system.reflection.emit.aspx

cary
A: 

you can look a .net compiler very simple there :

http://msdn.microsoft.com/en-us/magazine/cc136756.aspx

cary