HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

VB6/VBA Declaration (Dim) Syntax Parser

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
declarationparservb6dimsyntaxvba

Problem

As part of a project I'm working on, I've implemented a class that encapsulates the syntax for a vb6/vba Dim statement.

Given a line of code, the Parse method uses a regular expression to match the keyword's syntax and extract the relevant parts.

As it stands there's no support for some valid syntaxes, the following aren't currently supported:

'multiple declarations on the same line:
Dim foo As String, bar As String 

'multiple instructions on the same line:
Dim foo As String: Dim bar As String


But this question isn't about the code that's not yet implemented, it's about the approach taken; the regular expression works (for the so-far supported use cases), but it's quickly going to become a problem (read: mess), especially since DimSyntax isn't going to be the only ISyntax implementation in the code.

On the other hand, vb6 isn't likely to ever change in the future, so perhaps a well-crafted regex can do the job, if it won't need to be maintained?
`public class DimSyntax : ISyntax
{
// todo: ditch regex
private static readonly string _syntaxPattern =
@"^((?Dim)\s(?\w{1,30})\s?(As\s(?\w{1,30})))?";

private static readonly Regex _regex = new Regex(_syntaxPattern);

private readonly IVBTypeFactory _typeFactory;

public DimSyntax(IVBTypeFactory typeFactory, IIdentifier identifier)
{
_typeFactory = typeFactory;
_identifier = identifier;
}

private readonly IIdentifier _identifier;
public IIdentifier Identifier { get { return _identifier; } }

public string Keyword { get { return Keywords.Dim; } }

public ISyntax Parse(string line)
{
var code = line.Trim();

var match = _regex.Match(code);
if (!match.Success)
{
return null;
}

var nameGroup = match.Groups["name"];
var typeGroup = match.Groups["type"];
if (nameGroup == null || typeGroup == null)
{
return null;
}

var typ

Solution

Finally, a question where we can use Roslyn!

I won't review your own code but instead I whipped up this small showcase of how you might do it with the Roslyn compilers. Do note that it is rather ugly, not in the least because I am not entirely comfortable with it myself yet but also because I know little VB.NET and it appears some things are handled differently from the C# compiler. That being said, this sample implementation can parse both

Dim foo As String


and

Dim foo As String, bar As String


El codos:

using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
using Microsoft.CodeAnalysis.VisualBasic;

class Program
{
    static void Main(string[] args)
    {
        var stuffIWantToParse = "Dim foo As String, bar As String";

        var tree = VisualBasicSyntaxTree.ParseText(@"
            Module Module1
                 " + stuffIWantToParse +
            @" End Module
        ");

        var compilation = VisualBasicCompilation.Create("MyCompilation", syntaxTrees: new[] { tree });
        var moduleType = compilation.GetTypeByMetadataName("Module1");

        PrintVariableDeclarationByIndex(0, moduleType);
        PrintVariableDeclarationByIndex(1, moduleType);

        Console.Read();
    }

    private static void PrintVariableDeclarationByIndex(int i, INamedTypeSymbol moduleType)
    {
        var variable = moduleType.GetMembers().Skip(i).FirstOrDefault();

        var position = variable.Locations.First().SourceSpan.Start;
        var root = variable.Locations.First().SourceTree.GetRoot();
        var parent = root.FindToken(position).Parent;
        var node = parent.FirstAncestorOrSelf();
        var typeInfo = node.Declarators[i].AsClause;

        Console.WriteLine("Modifiers: " + string.Join(",", node.Modifiers));
        Console.WriteLine("Name: " + variable.Name);
        Console.WriteLine("Type: " + typeInfo.Type());
        Console.WriteLine();
    }
}


Output:

Using a workaround from here. If you want some more codesamples on Roslyn, look at my project here. In order to use the Visual Basic compilers look here. For more information on Roslyn, take a look at the roslyn tag wiki I put together.

Code Snippets

Dim foo As String
Dim foo As String, bar As String
using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
using Microsoft.CodeAnalysis.VisualBasic;

class Program
{
    static void Main(string[] args)
    {
        var stuffIWantToParse = "Dim foo As String, bar As String";

        var tree = VisualBasicSyntaxTree.ParseText(@"
            Module Module1
                 " + stuffIWantToParse +
            @" End Module
        ");

        var compilation = VisualBasicCompilation.Create("MyCompilation", syntaxTrees: new[] { tree });
        var moduleType = compilation.GetTypeByMetadataName("Module1");

        PrintVariableDeclarationByIndex(0, moduleType);
        PrintVariableDeclarationByIndex(1, moduleType);

        Console.Read();
    }

    private static void PrintVariableDeclarationByIndex(int i, INamedTypeSymbol moduleType)
    {
        var variable = moduleType.GetMembers().Skip(i).FirstOrDefault();

        var position = variable.Locations.First().SourceSpan.Start;
        var root = variable.Locations.First().SourceTree.GetRoot();
        var parent = root.FindToken(position).Parent;
        var node = parent.FirstAncestorOrSelf<FieldDeclarationSyntax>();
        var typeInfo = node.Declarators[i].AsClause;

        Console.WriteLine("Modifiers: " + string.Join(",", node.Modifiers));
        Console.WriteLine("Name: " + variable.Name);
        Console.WriteLine("Type: " + typeInfo.Type());
        Console.WriteLine();
    }
}

Context

StackExchange Code Review Q#53800, answer score: 3

Revisions (0)

No revisions yet.