Click here to Skip to main content
15,881,204 members
Articles / Programming Languages / C#
Article

Mini C# Compiler

Rate me:
Please Sign up or sign in to vote.
4.70/5 (10 votes)
25 Oct 2008CPOL2 min read 71.4K   7.6K   68   9
MiniCompiler is a simple application for compiling single file C# source code. I've used interfaces provided by the .NET platform.
MiniCom.png

Code Explanation

C# MiniCompiler is a simple application that uses CSharpCodeProvider to create an instance of C# code compiler, then uses ICodeCompiler for all .NET compilers like VB, J#. So if we want to compile C# code, assign the interface ICodeProvider to provider.CreateCompiler().

Now we have the engine that compiles the code. We don't do anything unless we give this engine (ICodeProvider) some information about the code we want to compile. You pass this information to CompilerParameters. This information includes the Main class as you should tell it the name of the main class which it cannot get by itself. It also includes OutPutAssembly name, and referenced assemblies. So we have two problems.
The first is to give CompilerParameters Main class. We can give it from TextBox (from user), but we don't want that. We want to make it get the Main class automatically. So I wrote a basic parser (ManiPulateMainClass.cs) that manipulates the Main class from the source code.
The second problem is referenced assemblies. We can give the compiled assembly some referenced assemblies, but it may need it and may not need others. We can also make the user choose his assemblies. But many users don't know the path of all assemblies. So, what I did is parse the referenced namespaces from the code, such as "using System.Windows;". If the compiler sees this statement, it references System.Windows.dll and so on...

ManiPulateManiPulateMainClass.cs

This class has some functions that split the source code in namespaces, then classes, then check each class to see if this class is the main class or not by searching for the Main() function:

C#
public static string GetMainClass(List<string> classname, List<string> classCode) 
{ 
    for (int i = 0; i < classCode.Count; i++) 
    { 
        if (classCode[i].Contains("Main(") && !classCode.Contains("\"")) 
        { 
            return classname[i]; 
        } 
    } 
    return "not found"; 
}

This function takes the class' sources codes as parameters and classNames that correspond to each class sourcecode. If it finds "Main()" without quotations, it means that it is the main class.

C#
public void CompileCSharp(string code,string outputassembly ) 
{ 
    CSharpCodeProvider provider = new CSharpCodeProvider(); 
    ICodeCompiler compiler = provider.CreateCompiler(); 
#region CompilerParameters 
    CompilerParameters parameters = new CompilerParameters() 
    { 
        MainClass = Classname(code), 
            GenerateExecutable = true, 
            OutputAssembly = outputassembly, 
            IncludeDebugInformation = true, 
    }; 
    parameters.ReferencedAssemblies.Clear(); 
    foreach (Assembly asm in assemblies) 
    { 
        parameters.ReferencedAssemblies.Add(asm.Location); 
    } 
#endregion 
    CompilerResults result = compiler.CompileAssemblyFromSource(parameters, code); 
    if (result.Errors.Count == 0) 
    { 
        if (!System.IO.File.Exists(outputassembly)) 
        { 
            OnFileNotExists(new EventArgs()); 
            return; 
        } 
        ProcessStartInfo startInfo = new ProcessStartInfo(); 
        startInfo.FileName =outputassembly; 
        startInfo.WindowStyle = ProcessWindowStyle.Maximized; 
        startInfo.Arguments = "\\S"; 
        Process process = new Process(); 
        process.StartInfo = startInfo; 
        process.Start(); 
        IntPtr hwnd = GetConsoleWindow(); 
        ShowWindow(hwnd, 0); 
    } 
    else 
    { 
        foreach (CompilerError er in result.Errors) 
        { 
            List<string> cerrors = new List<string>(); 
            cerrors.Clear(); 
            cerrors.Add(
                 er.ErrorText+ " Line ("+er.Line.ToString()+") error :"+er.ErrorNumber ); 
            OnCompilationError(new ErrorEventArgs(cerrors)); 
        } 
        result.Errors.Clear(); 
    } 
}

First, we use ICodeProvider interface to compile CSharpCode:

C#
ICodeCompiler compiler = provider.CreateCompiler();

Then, we create Compiler Parameters Object and give it some compilation information like the Main class. The Classname method uses the parser to get the Main class, so we call it to get the Main class name in this form, e.g.: Mynamespace.MyClass, OutPutAssembly property is the path of the output compiled program.

C#
CompilerParameters parameters = new CompilerParameters() 
{ 
    MainClass = Classname(code), 
        GenerateExecutable = true, 
        OutputAssembly = outputassembly, 
        IncludeDebugInformation = true, 
}; 
//here we populate the compiled program with referenced assemblies 
foreach (Assembly asm in assemblies) 
{ 
    parameters.ReferencedAssemblies.Add(asm.Location); 
}

I got the referenced assemblies by parsing the referenced namespaces, but it is not a robust method. First, I collect all the common assemblies by getting the assemblies directories from the registry:

C#
//get all assemblies directories 
public List<string> AssemblyDirectories() 
{ 
    List<string> assemblies = new List<string>(); 
    Microsoft.Win32.RegistryKey key = Registry.LocalMachine; 
    key = key.OpenSubKey(@"SOFTWARE\Microsoft\.NETFramework\AssemblyFolders"); 
    string[] SubKeynames = key.GetSubKeyNames(); 
    foreach (string subkeys in SubKeynames) 
    { 
        RegistryKey subkey = Registry.LocalMachine; 
        subkey = subkey.OpenSubKey(
            @"SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\" + subkeys); 
        string[] l = subkey.GetValueNames(); 
        foreach (string v in l) 
        { 
            if (subkey.GetValueKind(v) == RegistryValueKind.String) 
            { 
                string value = (string)subkey.GetValue(v); 
                assemblies.Add(value); 
            } 
        } 
    } 
    assemblies.Add( Environment. @":\Windows\Microsoft.NET\Framework\v2.0.50727"); 
    return assemblies; 
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Egypt Egypt
I am Student @ Misr University 4 Science & Technology , began programming at early age , when I was 14 ,I have worked with vb6 and java alot but now I am interesting in c# & .NET Technologies , My favourite Programming language is C++

Comments and Discussions

 
Questiontengo problemas el proyecto me sale error. Pin
Janero8915-May-15 15:07
Janero8915-May-15 15:07 
QuestionThe path is not of a legal form. Pin
hans94miguel7-Dec-14 18:55
hans94miguel7-Dec-14 18:55 
QuestionThanks! Pin
Manuel Calderón8-Nov-14 15:08
Manuel Calderón8-Nov-14 15:08 
AnswerRe: Thanks! Pin
Manuel Calderón8-Nov-14 15:13
Manuel Calderón8-Nov-14 15:13 
Questionnice work sir but got a question here Pin
Elegiac28-May-13 22:50
Elegiac28-May-13 22:50 
Generalmy vote of 5 Pin
88Rocker11-Nov-10 19:08
88Rocker11-Nov-10 19:08 
GeneralMy vote of 2 Pin
Sandeep Datta28-Oct-09 21:30
Sandeep Datta28-Oct-09 21:30 
The title is a misnomer. "Mini C# development environment" would have been more appropriate. I was looking for a real compiler with a lexer, parser and all but...
GeneralRe: My vote of 2 Pin
DelphiCoder21-Jun-12 10:01
DelphiCoder21-Jun-12 10:01 
QuestionHow to select the source file? Pin
andre1234530-Oct-08 1:03
andre1234530-Oct-08 1:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.