Friday, 29 August 2008

Use the CSParser to process C# files

I wanted to generate code but at the same time parse the target file first to see if any changes have been manually made or with the graphical designer.


I found the following parser for c# code: http://www.codeplex.com/csparser; it seems very active at the moment, and it parsed my test cs file without any problems.



I had some issues first understanding how to look for the current line number and how to know the name of the classes and methods etc. But a look at the sample file cmc.cs helped a lot.

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using DDW.Collections;
using DDW;
using Microsoft.CSharp;

namespace test
{
class Program
{
private static void PrintErrors(IEnumerable errors)
{
foreach (Parser.Error error in errors)
{
if(error.Token.ID == TokenID.Eof && error.Line == -1)
{
Console.WriteLine(error.Message + "\nFile: " + error.FileName + "\n");
}
else
{
Console.WriteLine(error.Message + " in token " + error.Token.ID
+ "\nline: " + error.Line + ", column: " + error.Column
+ "\nin file: " + error.FileName + "\n");
}
}
}

private static CompilationUnitNode ParseUnit(string fileName, List errors)
{
Console.Write("\nParsing " + fileName);
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs, true);
Lexer l = new Lexer(sr);
TokenCollection toks = l.Lex();

Parser p = null;
CompilationUnitNode cu = null;

p = new Parser(fileName);
cu = p.Parse(toks, l.StringLiterals);

if(p.Errors.Count != 0)
{
Console.WriteLine();
PrintErrors(p.Errors);
errors.AddRange(p.Errors);
return null;
}
return cu;
}

public static void Main(string[] args)
{
string filename = "c:\\myfile.cs";
List errors = new List();
CompilationUnitNode cu = ParseUnit(filename, errors);

StringBuilder sb = new StringBuilder();
cu.ToSource(sb);
Console.WriteLine(sb.ToString());
foreach (NamespaceNode nnode in cu.Namespaces)
{
foreach (ClassNode cnode in nnode.Classes)
{
Console.WriteLine("class name: " + cnode.Name.Identifier.ToString());
foreach (FieldNode fnode in cnode.Fields)
{
foreach (QualifiedIdentifierExpression qexpr in fnode.Names)
{
sb = new StringBuilder();
qexpr.Expressions.ToSource(sb);
Console.WriteLine("Field: " + sb.ToString());
}
}
foreach (MethodNode mnode in cnode.Methods)
{
sb = new StringBuilder();
mnode.Names.ToSource(sb);
if (sb.ToString() == "InitializeComponent")
{
Console.WriteLine("Line number of InitializeComponent starting: " +
mnode.RelatedToken.Line.ToString());
int firstLine = -1;
int lastLine = -1;
foreach (StatementNode snode in mnode.StatementBlock.Statements)
{
if (firstLine == -1)
{
firstLine = snode.RelatedToken.Line;
}
lastLine = snode.RelatedToken.Line;
sb = new StringBuilder();
snode.ToSource(sb);
string line = sb.ToString();
Console.Write(snode.RelatedToken.Line.ToString() + ": " + line);

}
}
}

}
}

Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}