Walkthrough: Using Managed Babel

This topic describes how to integrate a new language into Visual Studio by using the MPLex and MPPG tools together with Managed Babel.

Note

The MPLex and MPPG tools produce C# code. Therefore, this walkthrough contains only C# code.

Creating a Language Service

The following procedures use a standard VSPackage together with Managed Babel to integrate a new language into the Visual Studio language services framework. They also use the lexer and parser files that are included in the ManagedMyC sample, which demonstrates how to implement the colorization, brace matching, and error handling features.

To set up the VSPackage and the package structure

  1. Create a new Visual Studio Integration Package in C#, and name it YourManagedLanguageProject.

  2. Add the following references to the project:

    • Microsoft.VisualStudio.Package.LanguageService.9.0

    • Microsoft.VisualStudio.TextManager.Interop.8.0

  3. Under the project node, create the following folders:

    • Generated

    • Invariant

    • UserSupplied

  4. Copy the Managed Babel source code from the Visual Studio SDK installation path\VisualStudioIntegration\Common\Source\CSharp\Babel\ folder and paste it in the Invariant folder that you created.

  5. Copy the following ManagedMyC lexer and parser files from the Visual Studio SDK installation path\VisualStudioIntegration\Samples\IDE\CSharp\Example.ManagedMyC\Generated\ folder and paste it in the Generated folder that you created:

    • lexer.lex

    • parser.y

    • ErrorHandler.cs

    • LexDefs.cs

Adding User-Supplied Code

You must add some code to implement the Managed Babel interfaces and abstract classes. The following procedures show the least amount of code that is required to support colorization, brace matching, and error handling.

To add the user-supplied code

  1. Add the following C# class files to the UserSupplied folder:

    • Configuration.cs

    • LanguageService.cs

    • Package.cs

    • Resolver.cs

  2. Add the following code to the Package class. This code registers the package and declares the language service features that it supports. You should generate a new GUID for your package.

    using System;
    using System.Runtime.InteropServices;
    namespace Babel
    {
     [Microsoft.VisualStudio.Shell.ProvideService(typeof(Babel.LanguageService))]
      [Microsoft.VisualStudio.Shell.ProvideLanguageExtension(typeof(Babel.LanguageService), Configuration.Extension)]
        [Microsoft.VisualStudio.Shell.ProvideLanguageService(typeof(Babel.LanguageService), Configuration.Name, 0,
            EnableCommenting = true,
            MatchBraces = true,
            ShowMatchingBrace = true)]
        //generate a new GUID
        [Guid("00000000-0000-0000-0000-000000000000")]   
           class Package : BabelPackage
        {
        }
    }
    
  3. Add the following code to the LanguageService class. This class just declares the GUID of the language service and implements the GetFormatFilterList method by supplying the filter for files in your language. You should generate a new GUID for your language service.

    using System;
    using System.Runtime.InteropServices;
    
    namespace Babel
    {
        //generate a new GUID
        [Guid("00000000-0000-0000-0000-000000000000")]
        class LanguageService : BabelLanguageService
        {
            public override string GetFormatFilterList()
            {
                return "YourManaged File (*.ym)\n*.ym";
            }
        }
    }
    
  4. Add the following code to the Resolver.cs file. Resolver functionality will not be used in this walkthrough, but this code must be present to provide a default implementation of the IASTResolver interface.

    using System;
    using System.Collections.Generic;
    
    namespace Babel
    {
    public class Resolver : Babel.IASTResolver
    {
    #region IASTResolver Members
    public IList<Babel.Declaration> FindCompletions(object result, int line, int col)
    {
    return new List<Babel.Declaration>();
    }
    
    public IList<Babel.Declaration> FindMembers(object result, int line, int col)
    {
    List<Babel.Declaration> members = new List<Babel.Declaration>();
    return members;
    }
    
    public string FindQuickInfo(object result, int line, int col)
    {
    return null;
    }
    
    public IList<Babel.Method> FindMethods(object result, int line, int col, string name)
    {
    return new List<Babel.Method>();
    }
    #endregion
    }
    }
    
  5. Add the following code to the Configuration.cs file. This code sets the name and file name extension for your language, defines how comments and braces are formatted, and adds the colors that are used for colorization and maps them to token types.

    using System;
    using Microsoft.VisualStudio.Package;
    using Babel.Parser;
    using Microsoft.VisualStudio.TextManager.Interop;
    
    namespace Babel
    {
        public static partial class Configuration
        {
            public const string Name = "YourManagedLanguage";
            public const string Extension = ".ym";
    
            static CommentInfo commentInfo;
            public static CommentInfo MyCommentInfo { get { return commentInfo; } }
    
            static Configuration()
            {
                commentInfo.BlockEnd = "*/";
                commentInfo.BlockStart = "/*";
                commentInfo.LineStart = "??";
                commentInfo.UseLineComments = false;
    
                // default colors - currently, these need to be declared
                CreateColor("Keyword", COLORINDEX.CI_BLUE, COLORINDEX.CI_USERTEXT_BK);
                CreateColor("Comment", COLORINDEX.CI_DARKGREEN, COLORINDEX.CI_USERTEXT_BK);
                CreateColor("Identifier", COLORINDEX.CI_SYSPLAINTEXT_FG, COLORINDEX.CI_USERTEXT_BK);
                CreateColor("String", COLORINDEX.CI_PURPLE, COLORINDEX.CI_USERTEXT_BK);
                CreateColor("Number", COLORINDEX.CI_MAGENTA, COLORINDEX.CI_USERTEXT_BK);
                CreateColor("Text", COLORINDEX.CI_SYSPLAINTEXT_FG, COLORINDEX.CI_USERTEXT_BK);
                TokenColor error = CreateColor("Error", COLORINDEX.CI_RED, COLORINDEX.CI_USERTEXT_BK, false, true);
    
                //
                // map tokens to color classes
                //
                ColorToken((int)Tokens.KWIF, TokenType.Keyword, TokenColor.Keyword, TokenTriggers.None);
                ColorToken((int)Tokens.KWELSE, TokenType.Keyword, TokenColor.Keyword, TokenTriggers.None);
                ColorToken((int)Tokens.KWWHILE, TokenType.Keyword, TokenColor.Keyword, TokenTriggers.None);
                ColorToken((int)Tokens.KWFOR, TokenType.Keyword, TokenColor.Keyword, TokenTriggers.None);
                ColorToken((int)Tokens.KWRETURN, TokenType.Keyword, TokenColor.Keyword, TokenTriggers.None);
                ColorToken((int)Tokens.KWINT, TokenType.Keyword, TokenColor.Keyword, TokenTriggers.None);
                ColorToken((int)Tokens.KWVOID, TokenType.Keyword, TokenColor.Keyword, TokenTriggers.None);
                ColorToken((int)Tokens.NUMBER, TokenType.Literal, TokenColor.String, TokenTriggers.None);
                ColorToken((int)'(', TokenType.Delimiter, TokenColor.Text, TokenTriggers.MatchBraces);
                ColorToken((int)')', TokenType.Delimiter, TokenColor.Text, TokenTriggers.MatchBraces);
                ColorToken((int)'{', TokenType.Delimiter, TokenColor.Text, TokenTriggers.MatchBraces);
                ColorToken((int)'}', TokenType.Delimiter, TokenColor.Text, TokenTriggers.MatchBraces);
    
                //// Extra token values internal to the scanner
                ColorToken((int)Tokens.LEX_ERROR, TokenType.Text, error, TokenTriggers.None);
                ColorToken((int)Tokens.LEX_COMMENT, TokenType.Text, TokenColor.Comment, TokenTriggers.None);
    
            }
        }
    }
    

You must add special build steps to your project to run the MPLex and MPPG tools on your lexer and parser files.

To add the MPLexCompile and MPPGCompile build steps to your project

  1. Open YourManagedPackage.csproj in a text editor such as Notepad or in a second instance of Visual Studio.

  2. Add the following block at the end of the <ItemGroup> blocks and before the <PropertyGroup> blocks:

    <ItemGroup>
        <MPLexCompile Include="Generated\lexer.lex" />
        <MPPGCompile Include="Generated\parser.y" />
      </ItemGroup>
    
  3. Save the file. In the original instance of Visual Studio, you should see a message box that asks whether you want to reload the project. Click Reload.

  4. Now, your project should compile correctly.

To test the new language service

  1. Build and run the project.

  2. In another instance of Visual Studio, create a new file and save it as File.ym.

  3. In File.ym, type something that resembles the following code:

    /* this is a comment */
    int addInt (int bar)
    {
    int i;
    for (i = 0;i < bar; i = i + 2)
    {
    bar = bar + i;
    }
    return bar;
    }
    

    You should see that the commented text is green, the keywords int, for, and return are blue, and the numbers are magenta. If you add pairs of braces or parentheses to the file, they should be displayed on a gray background when they are matched.

See Also

Concepts

Managed Babel Essentials

Other Resources

Managed Babel

Change History

Date

History

Reason

July 2008

Rewrote and refactored project.

Content bug fix.

January 2010

Fixed assembly reference.

Content bug fix.