Apr 30, 2008

Compiler generator CoCo/R for C#


During the preparation for a project bid for one of my customers I recently came across the CoCo/R compiler generator tool. Coco/R is a compiler generator, which takes an attributed grammar Backus-Naur-Form ( BNF) of a source language and generates a C# (and many other languages) scanner and a parser for this language.

To play around I created a small language that can speak and show message boxes. The grammer .ATG file looks the following:


COMPILER Talk

public System.Speech.Synthesis.SpeechSynthesizer ss = new System.Speech.Synthesis.SpeechSynthesizer();

void Say(string text)
{
ss.Speak(text);
}

void Show(string text)
{
System.Windows.Forms.MessageBox.Show(text);
}

IGNORECASE
// The $L option let you compile directly within your grammar
// You can comment and uncomment the line to fit your development requirements.
$LM

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
CHARACTERS
digit = "0123456789".
cr = '\r'.
lf = '\n'.
tab = '\t'.
bslash = '\\'.
quote = '"'.
chars = ANY - digit - cr - lf - tab - bslash - quote.

TOKENS
string = quote { chars | digit} quote.

IGNORE cr + lf + tab

PRODUCTIONS

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Show
=
"Show" string (. Show(t.val); .)
.

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Say
=
"Say" string (. Say(t.val); .)
.

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Statement
=
Show | Say
.

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Statements
=
Statement ';' { Statement ';' }
.

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Talk
=
Statements
.

END Talk.


Please note the so-called semantic actions, like (. Say(t.val); .) that is executed when the corresponding token is parsed.

The code I had to write was reduced to the following:

private void btnTalk_Click(object sender, RoutedEventArgs e)
{
Parser p = new Parser(this.tbTalk.Text);
p.Parse();

tbOutput.Text = p.errors.count.ToString() + " errors";
}

Nice and easy.

Apr 22, 2008

Microsoft.TeamFoundation.WorkItemTracking.Client

I just figured out how easy it is to get access to TFS work items. In my case I was interested in linked work items of a given work item ID:

string workItemStore = ConfigurationManager.AppSettings["WorkItemStore"];

store = new WorkItemStore(workItemStore);


to connect to the TFS server and then

WorkItem m_workItem = store.GetWorkItem(int.Parse(this.tbID.Text));

 

if (m_workItem != null)

{

    lblWorkItem.Text = m_workItem.Title;

 

    foreach (Link link in m_workItem.Links)

    {

 

        RelatedLink rl = link as RelatedLink;

 

        if (rl != null)

        {

            WorkItem realtedWorkItem = m_workItem.Store.GetWorkItem(rl.RelatedWorkItemId);

            list.Add(realtedWorkItem);

        }

 

    }

}

 

dataGridView1.DataSource = list;


to list the linked work items in a simple grid.

When you want to query for WIs it should be possible to call:

// query retrieves all work items for the specified team project

string wiqlQuery = "SELECT [System.Id], [System.WorkItemType], [System.State], [System.AssignedTo], [System.Title] FROM WorkItems WHERE [System.TeamProject] = '" + teamProjectName + "' ORDER BY [System.WorkItemType], [System.Id]";

// execute the query and retrieve a collection of workitems

WorkItemCollection workitems = store.Projects[0].Store.Query(wiqlQuery);

// loop through work items

if (workitems.Count > 0)

{

    // select first Work Item

    retWi = workitems[0];

}


Note: To get rid of the assembly load exception just reference the shared assemblies from the disk path and do not use the GAC ones!