Prometi na palestra sobre MDD e Oslo neste TechEd colocar neste blog o código do exemplo de como usar uma gramática Mgrammar no .Net. Pois aqui vai....

A gramática que mostrei na demo é simples. Ela lê textos da forma “X tem Y anos.”. Um exemplo seria:

“Otavio tem 50 anos.

Paula tem 29 anos.”

Para isto, preciso declarar a gramática de reconhecimento em uma variável da forma:

static private string contactGrammar = @"
            module lingContato {
                language Contatos {
                    syntax Main = c:Contato * => Contatos { valuesof(c) };
                    syntax Contato =
                         n:Nome ""tem"" i:Idade ""anos."" => { Nome = n, Idade=i };
                    token Nome = ('A'.. 'Z' | 'a'..'z')+;
                    token Idade = '0'..'9'+;
                    interleave espaco = ' ' | '\r' | '\n' | '\r\n';
                }
            }";

O passo 2 é compilar a gramática e criar o “parser”:

CompilationResults resultsContatos = Compiler.Compile(
    new CompilerOptions
    {
        Sources = {
                    new TextItem {
                        Reader = new StringReader(contactGrammar),
                        ContentType = TextItemType.MGrammar
                    }
                }
    }
);

DynamicParser parserContatos = resultsContatos.ParserFactories["lingContato.Contatos"].Create();

parserContatos.GraphBuilder = new NodeGraphBuilder();

O passo 3 é fazer o “parsing”do texto de entrada (na variável inText), gerando um grafo que representa a AST (Abstract Syntax Tree).

Node nContato = (Node)parserContatos.Parse(new StringTextStream(inText), null);

Por fim, estamos prontos para navegar o texto e preencher uma lista do tipo Contato:

Contato c = new Contato();

foreach (Node record in tree.ViewAllNodes() )
{
    foreach (var member in record.Edges )
    {
        string s = member.Label + ": " + member.Node;

        if (member.Label == "Idade")
        {
            c.Idade = member.Node.ToString();
            lc.Add(c);
            c = new Contato();
            saida += s + " \r\n";
        }
        else
        {
            c.Nome = member.Node.ToString();
            saida += s + " ";
        }

    }
}

onde Contato é dado pela classe:

public class Contato {

     public string Nome { get; set; }

     public string Idade { get; set; }

}

Você vai precisar destas declarações de namespaces do Oslo (no diretório bin da instalação do SDK dele):

using Microsoft.M;
using Microsoft.M.Parser;
using Microsoft.M.Grammar;
using System.Dataflow;

Aqui abaixo vocês podem ver como fica esta exemplo no Intellipad do Oslo.

clip_image002

Na esquerda desta figura temos exemplos de frases de entrada. No meio, a gramática que consegue analisar sintaticamente este texto de entrada. Na esquerda vocês vêem a saida depois da análise. É um texto com chaves que representa uma AST (ou grafo).

Para quem não viu, temos um webCast similar em: https://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?culture=pt-BR&EventID=1032416175&CountryCode=BR

Vale a pena também ler os artigos:

Textual Domain Specific Languages for Developers - Part 1

Textual Domain Specific Languages for Developers - Part 2

Textual Domain Specific Languages for Developers - Part 3

Creio que com isto você consegue criar o seu parser, não consegue?

Promessa é divida. Com isto acabei de pagar a minha!

Abraços,

Otavio